docs, comments: the drift the audit listed (audit 2026-10-17, stage 6)
The lines under "Doc and comment drift" that the findings' own commits did not already fix: - security.md: a newer confirmation link replaces the older, a reset link is not replaced; html/template renders every page (no themes); the container keeps eight capabilities, named, not "KILL". - architecture.md: ImportKey writes over a name's key, as an import must; the error text reaches the browser on the Backup page's import refusal. - guide: with Caddy the key is in Caddy's data, so a full backup refuses until certs/ holds a copy (or back up caddy-data). - comments: sasldb2 holds application passwords in the clear (store, app/password.go); texthash folds ASCII (sender.go); the supervisor socket's group is supervisor (rpc.go); cert-reload's OpenSSL measurement was 3.0.x of bookworm; sendReset's limits (links.go). Migration 0013's comment stays as shipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -243,7 +243,9 @@ then OpenDKIM did, in a program of its own
|
||||
(`internal/domain`, `Keys`; `DKIM_DIR`, default `/data/dkim`). A key is
|
||||
made when a domain is added and an existing one is reused, never
|
||||
overwritten: that would invalidate the record already published
|
||||
(`EnsureKey`). A domain export carries the key and an import writes it. A
|
||||
(`EnsureKey`). A domain export carries the key and an import writes it,
|
||||
over whatever key the name had (`ImportKey`: the import is the domain
|
||||
with exactly that key). A
|
||||
deleted domain's key directory is removed once the selector table no
|
||||
longer names it; one a deletion had to leave, Reload configuration removes
|
||||
(`Service.Resync`).
|
||||
@@ -1031,7 +1033,8 @@ A validation refusal is shown as the text the validator wrote (on the form,
|
||||
next to the field, or in a notice above the first box). Anything else — a
|
||||
database error, `saslpasswd2`, a Postfix reload — is logged
|
||||
and the page gets a fixed sentence saying so; the error text never reaches the
|
||||
browser. A template error renders a bare `500` rather than a half-written page
|
||||
browser - save on the global-only Backup page, where an import's refusal
|
||||
names what is wrong with the file (security.md § Output and process). A template error renders a bare `500` rather than a half-written page
|
||||
(`Engine.Render` buffers).
|
||||
|
||||
### Sessions
|
||||
|
||||
@@ -407,6 +407,12 @@ docker compose -f docker-compose.yml -f caddy/docker-compose.caddy.yml up -d
|
||||
|
||||
Verify Caddy's on-disk cert path for your version before relying on the
|
||||
default mount — see the comment at the top of the Caddy compose fragment.
|
||||
With Caddy the certificate lives in Caddy's own data, not in `certs/`, and
|
||||
Caddy writes its keys readable by itself alone: the panel's full backup then
|
||||
refuses with "certs/ holds no certificate". Back up `./caddy/caddy-data`
|
||||
with the project directory instead, or keep a copy of the pair in `certs/`,
|
||||
the key given to group 10997 (`chgrp 10997`, `chmod 640`), refreshed after
|
||||
each renewal.
|
||||
|
||||
**Traefik (containerised).** Edit the `Host(...)` label and ACME email in
|
||||
[deploy/traefik/docker-compose.traefik.yml](../deploy/traefik/docker-compose.traefik.yml),
|
||||
|
||||
@@ -855,8 +855,11 @@ the argument.
|
||||
M6, M8 in code (a session from a longer window is cut at the next check;
|
||||
three headers signed; a long header line logged); A6, A7, W7 by wording
|
||||
in security.md - each is what the code should do; the README note.
|
||||
- [ ] **Doc drift sweep** — every line under "Doc and comment drift" above.
|
||||
— **Sonnet**, 1 h.
|
||||
- [x] **Doc drift sweep** — every line under "Doc and comment drift" above.
|
||||
— **Sonnet**, 1 h. *Done 2026-10-17:*
|
||||
every line, each with the finding that fixed it or in this sweep; left as
|
||||
history: migration `0013`'s comment (a migration is not edited after it
|
||||
shipped); the live compose is re-copied at the next rollout.
|
||||
- **Accept, with the argument:** *the setuid/setgid binaries of the base
|
||||
image* — inert under `no-new-privileges`, which the shipped compose sets
|
||||
and the e2e exercises; removing Debian's set is a maintenance cost at every
|
||||
|
||||
+10
-6
@@ -171,8 +171,10 @@ The panel is exposed to the internet — the items below are **not optional**.
|
||||
is 256 random bits (`crypto/rand`); `user_links` keeps its SHA-256 only,
|
||||
so the database or a backup opens nothing. A confirmation link lives 24
|
||||
hours, a reset link 30 minutes; each is taken once, in the transaction
|
||||
that deletes it (`DELETE … RETURNING`), and a newer link of the same kind
|
||||
replaces the older. A reset link holds only while the account's address is
|
||||
that deletes it (`DELETE … RETURNING`); a newer confirmation link replaces
|
||||
the older one, while a reset link is not replaced - the one in the mailbox
|
||||
works until it is used or expires, and another is not sent within ten
|
||||
minutes of it. A reset link holds only while the account's address is
|
||||
still the confirmed one it was sent to; a confirmation link only while the
|
||||
address is the one it confirms. The link's host is `SELFPOST_HOSTNAME`,
|
||||
never the request's `Host`, which an attacker would choose to receive the
|
||||
@@ -278,8 +280,8 @@ operator can act on it.
|
||||
|
||||
### Output and process
|
||||
|
||||
- Rendering goes through `html/template` with auto-escaping (queue, log,
|
||||
journal, themes).
|
||||
- Rendering goes through `html/template` with auto-escaping (queue, logs,
|
||||
journal, every page).
|
||||
- The panel process is **not root** (`user=panel` in supervisord); path access
|
||||
is granted through the `selfpost` group with minimal permissions. The
|
||||
supervisord control socket, which can stop or restart any program, is the
|
||||
@@ -299,8 +301,10 @@ operator can act on it.
|
||||
`2.14.4` the guide gave the key to `selfpost`, so every Postfix daemon -
|
||||
an smtpd talking to the internet included - could read it (security audit
|
||||
2026-10-17, I1; measured on the test server with `docker exec -u postfix`).
|
||||
- **The container keeps `KILL`** (`deploy/docker-compose.yml`, `cap_add`;
|
||||
every other capability not listed there is dropped). Without it root
|
||||
- **The container keeps eight capabilities**, `KILL` among them
|
||||
(`deploy/docker-compose.yml`, `cap_add`: NET_BIND_SERVICE, CHOWN, FOWNER,
|
||||
FSETID, SETUID, SETGID, DAC_OVERRIDE, KILL, each with its reason there;
|
||||
every other is dropped). Without it root
|
||||
cannot signal a process of another uid (kill(2), capabilities(7); measured
|
||||
on the test server, 2026-10-16), and two root processes must: supervisord
|
||||
stops and restarts the panel, and Postfix's master ends its children,
|
||||
|
||||
Reference in New Issue
Block a user