Hi, Attached is a small patch for two of the three CVEs in this bug. I found no upstream fix for either: dkim_qp_decode() is the same on upstream's develop branch as in 2.11.0 Beta2, and dkim_canon_selecthdrs() there still has the same loop. The patch applies to 2.11.0~beta2-9.2, 2.11.0~beta2-9.1 and 2.11.0~beta2-8+deb12u1 after their patch series. Bullseye was not checked.
CVE-2026-100888, dkim_canon_selecthdrs(): lhdrs has dkim_hdrcnt slots, but the loop stores NULL at lhdrs[shcnt] for every name in h=. Once all headers are used, shcnt equals dkim_hdrcnt, so one more name writes a NULL pointer one slot past the array. The patch stops the loop at that point; no unused header remains to be matched, so the result does not change. CVE-2026-100889, dkim_qp_decode(): the check is q <= end with end = out + outlen, so it stores outlen + 1 bytes. The callers in dkim.c that I read all pass the buffer size minus one, so in those the extra byte is still inside the buffer. It lands on the byte reserved for the terminator, and the callers that ignore the return value can be left with an unterminated string. I did not review other users of this exported function. Testing is limited. I did not reproduce either bug and did not write a trigger for them. I compiled the unpatched and patched functions with ASan and UBSan in a small harness with stubbed types, and ran valid inputs through them: 8 quoted-printable strings and 6 header lists, on all three versions above. Output was identical and the sanitizers reported nothing. That shows no regression on those inputs; it does not demonstrate the fixes. I did not build the full package or run its test suite. CVE-2026-101277 is not covered and I have not assessed it. Regards, Sumit Verma
Description: Fix one-slot overruns in dkim_canon_selecthdrs() and dkim_qp_decode() CVE-2026-100888: lhdrs has dkim_hdrcnt entries, but the loop stores NULL at lhdrs[shcnt] for each name in the signature's h= tag. Once every header has been used, shcnt equals dkim_hdrcnt and the next name writes past the array. Stop at that point; no unused header is left to match. . CVE-2026-100889: dkim_qp_decode() accepted q == end, storing one byte more than outlen. Use q < end. Author: Sumit Verma <[email protected]> Forwarded: no --- --- a/libopendkim/dkim-canon.c +++ b/libopendkim/dkim-canon.c @@ -1049,6 +1049,10 @@ shcnt = 0; for (c = 0; c < n; c++) { + /* lhdrs has one slot per header; once all are used, stop */ + if (shcnt >= dkim->dkim_hdrcnt) + break; + lhdrs[shcnt] = NULL; len = MIN(DKIM_MAXHEADER, strlen((char *) hdrs[c])); --- a/libopendkim/util.c +++ b/libopendkim/util.c @@ -364,7 +364,7 @@ { decode++; - if (q <= end) + if (q < end) { *q = *x; q++; @@ -400,7 +400,7 @@ { decode++; - if (q <= end) + if (q < end) { *q = *x; q++; @@ -410,7 +410,7 @@ start = NULL; stop = NULL; - if (q <= end) + if (q < end) { *q = xl; q++; @@ -442,7 +442,7 @@ { decode++; - if (q <= end) + if (q < end) { *q = *x; q++; @@ -454,7 +454,7 @@ { decode++; - if (q <= end) + if (q < end) { *q = '\n'; q++; @@ -463,12 +463,12 @@ else { decode += 2; - if (q <= end) + if (q < end) { *q = '\r'; q++; } - if (q <= end) + if (q < end) { *q = '\n'; q++; @@ -495,7 +495,7 @@ { decode++; - if (q <= end) + if (q < end) { *q = *x; q++;

