roadmap: own-mta-builds analysed - no own builds; three rows proposed instead
test / test (push) Canceled after 0s
test / test (push) Canceled after 0s
docs/own-mta-builds-2026-10-15.md weighs patched builds of Postfix and OpenDKIM against what the panel works around. No Postfix limit needs a patch (the panel reads it through the interfaces it offers); every limit worked around is OpenDKIM's, a project with no release since 2018, three 2026 CVEs open in every Debian suite and no one answering (read in dev/upstream: dkim_process_set runs on a tenant's DKIM-Signature header in signing mode too). Bookworm is in LTS since 2026-07-12 and its Postfix 3.7.11 lacks the June, August and September 2026 upstream security batches, which carry no CVE ids. Proposed as candidates: port25-bare-newline (smtpd_forbid_bare_newline defaults to no on 3.7; our smtp/inet block does not set it), base-trixie (postfix 3.10.13; 331 citation lines to re-read), panel-dkim-signing (go-msgauth/dkim in the panel's milter; OpenDKIM, the syslog relay and the parser port removed, about 1,500 lines). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,276 @@
|
||||
# Own builds of Postfix and OpenDKIM - the analysis of 2026-10-15
|
||||
|
||||
**Question (owner, 2026-10-15; roadmap [own-mta-builds](roadmap.md#own-mta-builds)):**
|
||||
is it worth patching Postfix and OpenDKIM and shipping our own builds, to
|
||||
optimise something in SelfPost or to lift a limit we work around?
|
||||
|
||||
**Answer:** no to carrying patched builds of either - nothing we work around
|
||||
needs a patch, and a patch set makes one maintainer the security team of
|
||||
two MTAs. The question does point at two real problems, each with a cheaper
|
||||
answer:
|
||||
|
||||
1. **The image's base is out of date.** `debian:bookworm-slim` left regular
|
||||
security support on 2026-07-12; its Postfix `3.7.11` is code of mid-2024,
|
||||
and the three Postfix security batches of 2026 (June, August, September)
|
||||
carry no CVE ids, so nothing will bring them to bookworm's LTS. The
|
||||
answer is Debian trixie (`postfix 3.10.13`, the August batch included),
|
||||
not a build of our own: proposed as roadmap row
|
||||
[base-trixie](roadmap.md#base-trixie).
|
||||
2. **OpenDKIM has no upstream left.** The package is a beta of 2018; three
|
||||
CVEs of 2026 are open in every Debian suite with "the vendor did not
|
||||
respond"; Debian's bug on them has had no answer since 2026-10-03. Every
|
||||
limit we have worked around is OpenDKIM's. A patched OpenDKIM of our own
|
||||
would make us its maintainer; signing in the panel's own milter, which
|
||||
already runs in the mail path, removes the program and most of what was
|
||||
built around it: proposed as roadmap row
|
||||
[panel-dkim-signing](roadmap.md#panel-dkim-signing).
|
||||
|
||||
A side finding of the reading: port 25 of the inbound relay accepts bare
|
||||
newlines - Postfix 3.7's default for the 2023 SMTP-smuggling parameter -
|
||||
one line fixes it: [port25-bare-newline](roadmap.md#port25-bare-newline).
|
||||
|
||||
Everything below is the evidence and the prices. Versions are those of the
|
||||
image (`docs/development.md`, the cited-package table); upstream source is
|
||||
`dev/upstream/`; web sources are linked where a fact came from one.
|
||||
|
||||
---
|
||||
|
||||
## 1. What the image runs, and who maintains it now
|
||||
|
||||
| Component | In the image (bookworm) | In Debian trixie | Upstream |
|
||||
|---|---|---|---|
|
||||
| Debian | 12 bookworm, LTS since 2026-07-12, until 2028-06-30 ([debian.org](https://www.debian.org/News/2026/20260712.en.html)) | 13 trixie, stable since 2025-08-09 | — |
|
||||
| Postfix | `3.7.11-0+deb12u1` (unchanged since the image was pinned; [tracker](https://tracker.debian.org/pkg/postfix)) | `3.10.13-0+deb13u1` (trixie-security) | `3.11.7`, stable branches 3.8–3.11 ([3.11.7](https://postfix.cs.utah.edu/announcements/postfix-3.11.7.html)) |
|
||||
| OpenDKIM | `2.11.0~beta2-8+deb12u1` | `2.11.0~beta2-9.1` (same code; a gcc-14 build fix, a path move, one verifier-side header patch) | `2.11.0-Beta2`, 2018; no release since ([releases](https://github.com/trusteddomainproject/OpenDKIM/releases), [issue #422](https://github.com/trusteddomainproject/OpenDKIM/issues/422), unanswered) |
|
||||
| libmilter | `8.17.1.9-2+deb12u2` | `8.18.1-6` | — |
|
||||
| Cyrus SASL | `2.1.28+dfsg-10` | `2.1.28+dfsg1-9` (same upstream) | — |
|
||||
| supervisor | `4.2.5-1` | `4.2.5-3` (same upstream) | — |
|
||||
| logrotate | `3.21.0-1` | `3.22.0-1` | — |
|
||||
| Go build stage | `golang:1.26-bookworm` | `golang:1.26-trixie` exists (Docker Hub, 2026-10-10) | — |
|
||||
|
||||
**Postfix in bookworm is 2024 code with the 2026 fixes missing.** Upstream
|
||||
issued three security batches this year, all without CVE ids:
|
||||
|
||||
- June 2026: unbounded reads of SMTP commands, responses and BDAT data
|
||||
("large SMTP inputs"); a TLSA-parsing crash (DANE only - not us).
|
||||
- August 2026 ([3.11.6](https://openwall.com/lists/oss-security/2026/08/20/5)):
|
||||
sixteen items, among them a remote memory exhaustion by many small BDAT
|
||||
commands (smtpd, since 3.4), a remote smtpd crash by DATA without MAIL
|
||||
FROM after a BDAT error, a policy bypass after an
|
||||
`smtpd_end_of_data_restrictions` reject (we set none), and the Milter
|
||||
left in "accept" state by the same bug.
|
||||
- September 2026 ([3.11.7](https://postfix.cs.utah.edu/announcements/postfix-3.11.7.html)):
|
||||
two SMTP-smuggling cases behind `smtpd_proxy_filter` (we use none), a
|
||||
crash under `strict_smtputf8` (not set), a multi-line response over-read
|
||||
reachable by a malicious Milter, a `postqueue` use-after-free.
|
||||
|
||||
Legacy releases 3.7.22 and 3.7.23 exist upstream but, as the announcements
|
||||
say, "do not include the patches for out-of-support Postfix versions" of
|
||||
June. Debian's tracker lists one 2026 CVE for bookworm's Postfix
|
||||
([CVE-2026-43964](https://security-tracker.debian.org/tracker/CVE-2026-43964),
|
||||
a one-byte over-read, `no-dsa`) and no bookworm upload at all in 2026; the
|
||||
LTS team works from CVE ids, and these batches have none. The exposed
|
||||
listeners are ours: 465 and 587 to the Internet, 25 when the inbound relay
|
||||
is on.
|
||||
|
||||
**OpenDKIM has three open CVEs and nobody to fix them.** Debian bug
|
||||
[#1149875](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1149875)
|
||||
(2026-10-03, severity important, no reply from maintainer or security team
|
||||
as of 2026-10-15) covers
|
||||
[CVE-2026-100888](https://security-tracker.debian.org/tracker/CVE-2026-100888)
|
||||
(`dkim_canon_selecthdrs`, out-of-bounds write),
|
||||
[CVE-2026-100889](https://security-tracker.debian.org/tracker/CVE-2026-100889)
|
||||
(`dkim_qp_decode`, off-by-one) and
|
||||
[CVE-2026-101277](https://security-tracker.debian.org/tracker/CVE-2026-101277)
|
||||
(`dkim_process_set`, the tag tokenizer); all three "vendor was contacted
|
||||
early but did not respond in any way". Read in `dev/upstream/opendkim-2.11.0~beta2`
|
||||
for our configuration (`Mode s`, attached to 465/587 and to the panel's
|
||||
local submission only; never to port 25):
|
||||
|
||||
- `dkim_qp_decode` is called from `dkim_sig_domainok()`,
|
||||
`dkim_sig_getreportinfo()` and `dkim_sig_getidentity()`
|
||||
(`libopendkim/dkim.c:1718, 7712, 7732, 7801`) - verifier-side functions,
|
||||
reached from `dkim_eoh_verify()`. Not on our path.
|
||||
- `dkim_process_set` runs on every `DKIM-Signature:` header of a message
|
||||
**in either mode**: `dkim_header()` (`dkim.c:6447`, the call at `:6625`)
|
||||
has no mode gate. On our path that header comes only from an authenticated
|
||||
application; the exposure is a tenant's, not the Internet's.
|
||||
- `dkim_canon_selecthdrs` runs when signing as well as when verifying
|
||||
(`dkim_canon_runheaders()`, `dkim-canon.c:1194, 1280`). The write past
|
||||
the array is `lhdrs[shcnt] = NULL` (`dkim-canon.c:1052`) once every
|
||||
header of the message has been matched and a further name follows. When
|
||||
verifying, the names are the signature's `h=`, the attacker's. When
|
||||
signing, OpenDKIM composes the list itself - the headers present that
|
||||
are in `SignHeaders` (by default RFC 6376 § 5.4's SHOULD list,
|
||||
`dkim_should_signhdrs[]`, `dkim.c:223`) plus `OversignHeaders`, our
|
||||
`From` - so the condition is a message whose every header is in that
|
||||
list. Whether Postfix's own `Received:` keeps it out of reach I did not
|
||||
run; it is one ASan run with `miltertest` on the stand to know, and the
|
||||
answer changes only how soon § 4's row is wanted, not whether.
|
||||
|
||||
A patch for each exists in the researchers' write-ups (for `dkim_qp_decode`:
|
||||
[weitongli.com](https://weitongli.com/share/opendkim-qp-off-by-one.html)).
|
||||
Nobody upstream will take them; Debian may yet carry them - the bug is
|
||||
twelve days old - but the project behind the package is gone, and the
|
||||
next finding meets the same silence.
|
||||
|
||||
## 2. The limits met so far, and what would lift each
|
||||
|
||||
| Limit (where it is worked around) | Own patched build | Debian trixie | Signing in the panel |
|
||||
|---|---|---|---|
|
||||
| OpenDKIM logs through syslog(3) only (`internal/syslogrelay`, a supervisord program, `/dev/log` in the entrypoint; audit L30) | yes, a stderr patch | no | yes - the program goes, and the relay with it (nothing else in the container uses syslog(3)) |
|
||||
| The panel reads Postfix's state from `mail.log`, `postconf -h -x`, `postqueue -p`/`-j` | no: these *are* Postfix's interfaces; a patch would invent a private one to maintain | partly: 3.11 adds `postconf -j` (JSON) - not in trixie's 3.10 | no (unchanged) |
|
||||
| The sender check reads `From:` the way OpenDKIM does: `dkim_mail_parse()` ported (`internal/milter/mailparse.go`, 327 lines), the 256-byte `MAXADDRESS` refusal, two diff/probe scripts against the C | no: the port exists because two programs parse the line; a patch does not merge them (OpenDKIM's `SenderMacro` could pick the key by the envelope instead - it changes nothing, since the check already pins `From:` to the login's senders) | no | yes: one parser, ours, and the key chosen by the login's domain, not by `From:` - the class "signed with another tenant's key" is gone by construction; `From:` still has to be the application's (DMARC alignment), with `net/mail` |
|
||||
| The image held to bookworm's versions (Postfix 3.7.11, OpenDKIM 2.11.0~beta2) | yes, at the price in § 3 | yes for Postfix (3.10.13, security-tracked to 2028 and beyond in trixie LTS); OpenDKIM's version is the same everywhere | OpenDKIM's version stops mattering |
|
||||
| A socket file outlives a crashed OpenDKIM (`health/socket.go`, assumptions #38) | yes, with a patch | no | yes - no second milter process |
|
||||
| Keys group-readable, `RequireSafeKeys no`, the `selfpost` group between panel and OpenDKIM | no | no | yes - the panel reads its own keys; the group stays for Postfix's sasldb and maps |
|
||||
| `SIGUSR1` through supervisord to reload the tables, which is what needs `CAP_KILL` in the compose file (cross-uid kill) | no | no | yes - no tables, no signal; `CAP_KILL` can probably go (to verify on the stand: supervisord then signals only root's wrapper and the panel's own uid) |
|
||||
| `smtpd_forbid_bare_newline` defaults to `no` on Postfix < 3.9 (`src/smtpd/smtpd.c:807`); our port 25 does not set it | yes | yes - the default is `normalize` since 3.9 | no (it is Postfix's) - see § 5 |
|
||||
|
||||
Nothing in the Postfix column needs a patch. The limits are OpenDKIM's.
|
||||
|
||||
## 3. The options, priced
|
||||
|
||||
Prices are estimates in stages of the kind the 2026-10-12 audit used (a
|
||||
stage: write, tests, two reviews, e2e, rollout, commit). Nothing here was
|
||||
measured on the stand; where a number matters it says so.
|
||||
|
||||
### A. Patched builds of both, carried by us - **not recommended**
|
||||
|
||||
- *Gives:* the stderr patch for OpenDKIM, the three CVE fixes, any option
|
||||
compiled in or out, the newest Postfix on the day we rebuild.
|
||||
- *Costs, once:* a build stage per program (`apt-get source`, quilt, a
|
||||
patch series, `dpkg-buildpackage`), its build-dependencies, the e2e
|
||||
`checkCitedPackageVersions` rewritten for our version strings, every
|
||||
citation of `3.7.11` (331 lines in 65 files) and `2.11.0~beta2` (55 in
|
||||
14) re-pointed at our tree. Image build time is not measured; from the
|
||||
size of the sources it is minutes, not seconds, on every rebuild.
|
||||
- *Costs, for ever:* Postfix issued seven releases in 2026; each is ours
|
||||
to notice, rebase the series on, rebuild and roll out, with no Debian
|
||||
security team between the announcement and the image. For OpenDKIM there
|
||||
is no upstream to rebase on at all: the series *is* the program, and
|
||||
the next CVE is ours to find and fix. One maintainer, two MTAs.
|
||||
- *Why not:* § 2 shows no Postfix limit a patch lifts, and every OpenDKIM
|
||||
limit lifted by option E without taking OpenDKIM on.
|
||||
|
||||
### B. Unpatched upstream build where the distribution's version is the limit - **not recommended**
|
||||
|
||||
- *Gives:* Postfix 3.11.7 today instead of trixie's 3.10.13 - the
|
||||
September batch two to four weeks earlier (trixie-security carried 3.10.11
|
||||
→ 3.10.12 → 3.10.13 between July and August; 3.10.14 is upstream now).
|
||||
For OpenDKIM there is no newer upstream to build.
|
||||
- *Costs:* A's build stage and watching duty for Postfix, minus the patch
|
||||
series; Debian's own patches (paths, SASL and LMDB build options)
|
||||
become ours to reproduce.
|
||||
- *Why not:* the gap to trixie-security is weeks, the duty is permanent.
|
||||
|
||||
### C. A patch sent upstream instead of carried - **nothing to send**
|
||||
|
||||
- Postfix: no code change is needed (§ 2); Wietse Venema's project is
|
||||
responsive, but we have no patch for it.
|
||||
- OpenDKIM: the project does not answer CVE reporters, the Debian
|
||||
maintainer or its own issue tracker. A patch sent there is a patch
|
||||
carried - option A.
|
||||
|
||||
### D. The base image to Debian trixie - **recommended, next code row** → [base-trixie](roadmap.md#base-trixie)
|
||||
|
||||
- *Gives:* Postfix 3.10.13 with the June and August batches and the
|
||||
September one when trixie-security ships 3.10.14; Debian's security team
|
||||
until 2028, then trixie LTS; `smtpd_forbid_bare_newline=normalize` by
|
||||
default; `smtpd_hide_client_session` (3.10: a `Received:` header without
|
||||
the application's address - a product question of its own, not decided
|
||||
here); OpenSSL 3.5; libmilter 8.18.1.
|
||||
- *Costs:* one stage, one MINOR release. The work is the re-reading: the
|
||||
331 citation lines against the 3.10.13 tree (most will hold word for
|
||||
word; `src/` paths are stable), with attention to what 3.8–3.10 changed
|
||||
on our paths - reject logging now carries `sasl_method`, `sasl_username`,
|
||||
`sasl_sender` (3.10, 20241023: `refusals.go`, `inbound.go` regexes), the
|
||||
queue id or `NOQUEUE` on an abnormal connection end and cleanup's
|
||||
`canceled` line (3.10: new line shapes for the log tailer), `postfix(1)`
|
||||
logging to stderr when it is not a terminal (3.8: the wrapper's output
|
||||
under supervisord), DNS results capped at 100 records and stray CR/LF
|
||||
replaced by default (3.9), the removed parameters (3.9:
|
||||
`permit_naked_ip_address`, `reject_maps_rbl`, `check_relay_domains` - we
|
||||
set none). Then: `dev/upstream` refetched from trixie, the cited-package
|
||||
table and `checkCitedPackageVersions`, the e2e sink image, the build
|
||||
stage tag, `docs/assumptions-2026-10-14.md`'s header, the guide's
|
||||
"what the image contains". OpenDKIM's citations do not change (same
|
||||
upstream code).
|
||||
- *Risk:* a log line we parse changing shape unnoticed - the e2e suite
|
||||
and the fixtures labelled "seen" are the net; a day on the test server
|
||||
before the cut.
|
||||
|
||||
### E. DKIM signing in the panel's own milter; OpenDKIM removed - **recommended, after D** → [panel-dkim-signing](roadmap.md#panel-dkim-signing)
|
||||
|
||||
- *Gives:* every OpenDKIM row of § 2; about 1,500 lines gone (the relay
|
||||
and its tests, the parser port and its tests, the probe scripts, the
|
||||
table renderer and its reload, `opendkim.conf`), two programs fewer
|
||||
under supervisord, two packages fewer in the image, no CVE watch on a
|
||||
dead project, probably `CAP_KILL` dropped. Keys, selectors and the
|
||||
published DNS records are unchanged: the panel already generates the
|
||||
keys (`internal/domain/dkim.go`, PKCS#1 PEM) - nothing for an operator
|
||||
to do.
|
||||
- *How:* `github.com/emersion/go-msgauth/dkim` (v0.7.0, 2025-04, MIT; the
|
||||
author of the `go-milter` we run; the e2e suite already verifies with it).
|
||||
Read for this analysis: `SignOptions` gives `relaxed`/`simple` per side,
|
||||
`HeaderKeys` with over-signing as RFC 6376 § 5.4.2 wants it (a name
|
||||
listed once more than present is kept in `h=` and nothing is hashed for
|
||||
it, `sign.go`), last-instance-first header picking (`header.go`), RSA and
|
||||
Ed25519, and a streaming `NewSigner` (the body is hashed as it passes,
|
||||
not buffered). The milter: headers and body chunks in, `InsertHeader(0,
|
||||
"DKIM-Signature", …)` at end of message - the shape of go-msgauth's own
|
||||
`cmd/dkim-milter`, some 450 lines. The key: by the login's domain on
|
||||
465/587 (`Bindings.DomainOf`, which the sender check has), by the
|
||||
server's name for the panel's local submission (`non_smtpd_milters`
|
||||
pointed at the same socket - strict, as OpenDKIM is today). The header
|
||||
set: `dkim_should_signhdrs[]`, `From` over-signed once; canonicalization
|
||||
`relaxed/simple`, as now.
|
||||
- *Costs:* two to three stages, one MINOR release: the signer and its
|
||||
tests; the removal (code, image, compose, supervisord, entrypoint,
|
||||
Health's liveness set, Resync's steps, docs: architecture § OpenDKIM,
|
||||
security, guide, development's table, assumptions § 3); e2e with an
|
||||
**independent verifier as the oracle** - go-msgauth must not check its
|
||||
own work: `opendkim-testmsg` in the sink image or rspamd's verifier, the
|
||||
way `mailparse-diff.sh` holds the port to the C today - and a message to
|
||||
a real mailbox before the cut.
|
||||
- *Risk:* a signing defect fails DMARC for every tenant at once; the
|
||||
oracle and the canary are the answer. go-msgauth is a small library with
|
||||
a quiet release pace - vendorable if it ever matters.
|
||||
- *Why after D:* D's exposure is remote and unauthenticated (465/587),
|
||||
E's is a tenant's; D is one stage, E is three; neither waits on the
|
||||
other (E re-reads no Postfix citation, D no OpenDKIM one).
|
||||
|
||||
## 4. Recommendation
|
||||
|
||||
In this order, each a roadmap row of its own, none of them an own build:
|
||||
|
||||
1. **[port25-bare-newline](roadmap.md#port25-bare-newline)** - one line in
|
||||
`build/postfix-config.sh`, a PATCH release, now (§ 5).
|
||||
2. **[base-trixie](roadmap.md#base-trixie)** - option D, one stage, MINOR.
|
||||
3. **[panel-dkim-signing](roadmap.md#panel-dkim-signing)** - option E, two
|
||||
to three stages, MINOR.
|
||||
|
||||
Options A, B and C are declined with the arguments above; what would bring
|
||||
A back is a limit of Postfix's that its interfaces cannot answer, and none
|
||||
is known.
|
||||
|
||||
## 5. Side finding: bare newlines on port 25
|
||||
|
||||
Postfix 3.7.11 has the 2023 SMTP-smuggling parameter
|
||||
(`smtpd_forbid_bare_newline`, `src/global/mail_params.h:4249`) with the
|
||||
default `no` "for Postfix < 3.9" (`src/smtpd/smtpd.c:807`); its
|
||||
`RELEASE_NOTES` recommend `normalize`, which 3.9 made the default. The
|
||||
inbound relay's listener (`build/postfix-config.sh`, the `smtp/inet`
|
||||
block) does not set it, so with `INBOUND_RELAY_ENABLE=true` the relay is
|
||||
the receiving side the smuggling research described: a bare `<LF>.<LF>`
|
||||
inside DATA ends the message early and what follows is read as the next
|
||||
transaction. Ports 465 and 587 are not the case that matters - the
|
||||
smuggled transaction is still the authenticated session's, under its
|
||||
sender bindings and milters. The fix is
|
||||
`smtp/inet/smtpd_forbid_bare_newline=normalize` with an e2e check on port
|
||||
25 (a bare-LF DATA, one message delivered); a PATCH release. Trixie's 3.10
|
||||
would set it by default, but the relay should not wait for that row.
|
||||
|
||||
A smaller one: `opendkim-tools` is installed in the image and used by
|
||||
nothing at run time (the key is generated in Go; the probe script runs on
|
||||
the server from source). It goes with option E, or with D if E waits.
|
||||
+87
-1
@@ -41,7 +41,10 @@ in `git log` and [CHANGELOG.md](../CHANGELOG.md).
|
||||
| notification-mail-recheck | The Notification mail records on Server › Settings can be checked again from where they are shown | agreed (2026-10-15) | — | — |
|
||||
| settings-save-row | Server › Settings: the Save button no longer stands alone under a long right column | agreed (2026-10-15) | — | — |
|
||||
| dns-record-collapse | A DNS record that is right is shown folded: its name and its tag, the values on request | agreed (2026-10-15) | — | — |
|
||||
| own-mta-builds | Analysis: build Postfix and OpenDKIM ourselves, patched, instead of Debian's packages | candidate (analysis, 2026-10-15) | — | — |
|
||||
| own-mta-builds | Analysis: build Postfix and OpenDKIM ourselves, patched, instead of Debian's packages | analysed 2026-10-15: no own builds; three rows proposed instead | — | [own-mta-builds-2026-10-15.md](own-mta-builds-2026-10-15.md) |
|
||||
| port25-bare-newline | The inbound relay's port 25 refuses bare newlines in DATA (`smtpd_forbid_bare_newline=normalize`) | candidate (2026-10-15, from own-mta-builds; recommended now, PATCH) | — | — |
|
||||
| base-trixie | The image's base from Debian bookworm (LTS since 2026-07-12) to trixie: Postfix 3.10 with the 2026 security batches | candidate (2026-10-15, from own-mta-builds; recommended next, MINOR) | — | — |
|
||||
| panel-dkim-signing | DKIM signing in the panel's own milter; OpenDKIM, the syslog relay and the parser port removed | candidate (2026-10-15, from own-mta-builds; recommended after base-trixie, MINOR) | — | — |
|
||||
| phone-desktop-mode | A phone browser in "desktop site" mode gets the phone navigation | agreed (2026-10-13: after stages 1 and 2 of audit-2026-10-12) | — | — |
|
||||
| from-header-binding | Hold a message's `From:` header against the application that sends it | shipped `2.4.0` | 9/9 | [plans/from-header-binding.md](plans/from-header-binding.md) |
|
||||
| panel-redesign | Panel redesign (accepted mockups, design contract) | shipped `2.0.0` | 27/27 | [plans/panel-redesign.md](plans/panel-redesign.md) |
|
||||
@@ -770,6 +773,89 @@ beyond the analysis.
|
||||
our own would remove, what each costs to keep, and whether a middle way
|
||||
gets the same for less.
|
||||
|
||||
**Outcome (2026-10-15):** [own-mta-builds-2026-10-15.md](own-mta-builds-2026-10-15.md).
|
||||
No own builds: no limit of Postfix's needs a patch (the panel reads it
|
||||
through the interfaces it offers), and every limit worked around is
|
||||
OpenDKIM's - a project with no release since 2018, three CVEs of 2026 open
|
||||
in every Debian suite and no one answering. What the question pointed at
|
||||
is answered by three rows instead, in this order:
|
||||
[port25-bare-newline](#port25-bare-newline) (one line, now),
|
||||
[base-trixie](#base-trixie) (bookworm is in LTS since 2026-07-12 and its
|
||||
Postfix 3.7.11 lacks the three 2026 security batches, which carry no CVE
|
||||
ids and so will not come), and
|
||||
[panel-dkim-signing](#panel-dkim-signing) (signing in the panel's own
|
||||
milter; OpenDKIM, the syslog relay and the parser port go). Each needs
|
||||
the owner's OK.
|
||||
|
||||
## port25-bare-newline
|
||||
|
||||
**Finding (own-mta-builds, 2026-10-15):** Postfix 3.7.11 has the 2023
|
||||
SMTP-smuggling parameter `smtpd_forbid_bare_newline` with the default `no`
|
||||
(`src/smtpd/smtpd.c:807`, "Postfix < 3.9: no"; 3.9 made `normalize` the
|
||||
default and the 3.7 `RELEASE_NOTES` recommend it). The inbound relay's
|
||||
`smtp/inet` block in `build/postfix-config.sh` does not set it, so with
|
||||
`INBOUND_RELAY_ENABLE=true` a bare `<LF>.<LF>` inside DATA ends the
|
||||
message early and what follows is read as the next transaction. Ports 465
|
||||
and 587 are not the case that matters: there the smuggled transaction is
|
||||
still the authenticated session's, under its bindings and milters.
|
||||
|
||||
**Goal:** `smtp/inet/smtpd_forbid_bare_newline=normalize`, an e2e check on
|
||||
port 25 (a bare-LF DATA, one message delivered, nothing smuggled), a
|
||||
PATCH release. [base-trixie](#base-trixie) would bring the default, but
|
||||
the relay should not wait for it.
|
||||
|
||||
## base-trixie
|
||||
|
||||
**Problem (own-mta-builds, 2026-10-15):** the image's base,
|
||||
`debian:bookworm-slim`, left regular security support on 2026-07-12 (LTS
|
||||
until 2028-06-30). Its `postfix 3.7.11-0+deb12u1` is code of mid-2024;
|
||||
upstream's three security batches of 2026 (June: unbounded SMTP inputs;
|
||||
August: BDAT memory exhaustion, a DATA crash, a policy bypass; September:
|
||||
smuggling behind a proxy filter, a Milter-reachable over-read) carry no
|
||||
CVE ids, and the LTS team works from CVE ids - no bookworm upload in 2026.
|
||||
Trixie's `postfix 3.10.13-0+deb13u1` has the August batch; 3.10.14 with
|
||||
September's is upstream and trixie-security follows within weeks.
|
||||
|
||||
**Goal:** `debian:trixie-slim` and `golang:1.26-trixie`; every citation of
|
||||
`3.7.11` (331 lines in 65 files) re-read against the 3.10.13 tree, with
|
||||
attention to 3.10's reject logging (`sasl_method`, `sasl_username`,
|
||||
`sasl_sender` on the line), the queue id on an abnormal connection end,
|
||||
cleanup's `canceled` line, 3.8's `postfix(1)` stderr logging under
|
||||
supervisord; `dev/upstream` refetched from trixie; the cited-package table
|
||||
and `checkCitedPackageVersions`; the e2e sink image; `opendkim-tools`
|
||||
dropped from the image (used by nothing at run time). OpenDKIM's code is
|
||||
the same in trixie, its citations stand. One stage, a MINOR release. Also
|
||||
gained: `smtpd_hide_client_session` (3.10) is available - whether the
|
||||
relay should hide the application's address from `Received:` is a product
|
||||
question to decide separately.
|
||||
|
||||
## panel-dkim-signing
|
||||
|
||||
**Problem (own-mta-builds, 2026-10-15):** OpenDKIM is a beta of 2018 with
|
||||
no upstream answering (CVE-2026-100888, -100889, -101277 open in every
|
||||
Debian suite, "vendor did not respond"; Debian bug #1149875 unanswered).
|
||||
Every limit SelfPost works around is its: it logs through syslog(3) only
|
||||
(the relay), it chooses the key by `From:` with its own parser (the port,
|
||||
the 256-byte refusal, the probe scripts), its socket file outlives a
|
||||
crash, its tables are reloaded by a cross-uid signal (`CAP_KILL`), its
|
||||
keys must be shared through a group.
|
||||
|
||||
**Goal:** the panel's own milter signs - `github.com/emersion/go-msgauth/dkim`
|
||||
(the e2e suite's verifier already; `relaxed/simple`, `From` over-signed,
|
||||
RFC 6376 § 5.4's header set, the body hashed as it streams), the key by
|
||||
the login's domain on 465/587 and by the server's name for the panel's
|
||||
local submission (`non_smtpd_milters` on the same socket, strict).
|
||||
Removed: the `opendkim` and `opendkim-tools` packages, `opendkim.conf`,
|
||||
two supervisord programs (OpenDKIM, the syslog relay), the table renderer
|
||||
and its reload, the parser port and its scripts, Health's OpenDKIM
|
||||
entries, probably `CAP_KILL` - about 1,500 lines. Keys, selectors and
|
||||
published DNS records unchanged; nothing for an operator to do. The e2e
|
||||
oracle must be an independent verifier (`opendkim-testmsg` in the sink
|
||||
image, or rspamd), not the signing library, and a message to a real
|
||||
mailbox precedes the cut. Two to three stages, a MINOR release; after
|
||||
[base-trixie](#base-trixie) (remote exposure first; the two touch
|
||||
disjoint citations).
|
||||
|
||||
## settings-save-row
|
||||
|
||||
**Problem (owner, 2026-10-15, a screenshot of `selfpost.mixfed.ru`):** on
|
||||
|
||||
Reference in New Issue
Block a user