51. pepsi-stage-vks-confirm

Follow a key server’s address-verification link, and nothing else.

51.1. Role

A key uploaded to a verifying key server is stored but not findable by address until somebody follows a link in a mail the server sends to that address. pepsi-stage-vks-confirm does that, on the inbound path, so key publication completes without a human reading every user’s mailbox.

It exists as a separate program because of what it is: something that fetches URLs found in inbound mail. That is a dangerous primitive, and putting it in its own small, unprivileged stage keeps it out of the programs that hold key material or parse hostile ciphertext, and makes its position in the pipeline visible in the configuration. Reference: pepsi-stage-vks-confirm(1).

Everything it does not act on — nearly all mail — is advanced to NEXT_STAGE untouched, so placement is forgiving.

51.2. What it refuses

Every one of these must hold before a byte is fetched. Failing any of them means the message is delivered instead, and the user can click the link themselves — which is what lets the conditions be this strict.

  • The envelope sender’s domain is exactly VKS_HOST, not a subdomain, not a suffix match, and not the From: header.

  • SPF or DMARC passed. A MAIL FROM is a claim; this is what turns it into evidence. dkim=pass deliberately does not count — it says a signature verified, not whose.

  • Every link points at that same host. A message naming any other host is refused entirely rather than having the foreign link skipped: a genuine verification mail links to the key server and nowhere else. The host is read after any userinfo, because https://keys.example.org@evil.test/ is a request to evil.test.

  • A recipient is an address we are actually waiting on — published, uploaded, not yet verified. An unsolicited verification mail is delivered, not clicked, which is also what stops a stranger making Pepsi issue requests by mailing a served address.

  • At most MAX_LINKS per message, fetched through the same hardened client key discovery uses: HTTPS only, certificates verified, the resolved address vetted against the SSRF guard, the body capped while streaming.

51.3. Confirmation is verified, not assumed

A 200 from the link is the server’s answer to a request, not a statement that the address is now published. The stage therefore asks the key server whether it serves our key for the address, and only a fingerprint match records the identity as verified — marking it on the 200 would stop pepsi-keys’s retry job from ever trying again.

Every decision and every fetch is logged at info on the vks-confirm target, which is the audit trail.

51.4. Configuration

[stage-<name>]: PROGRAM = pepsi-stage-vks-confirm, NEXT_STAGE (required — see above), VKS_HOST (defaulting to the host of [pepsi-keys] VKS_SERVER), MAX_LINKS (3), DISCARD_CONFIRMED (yes: the confirmation mail is machine mail about an action Pepsi took) and REQUIRE_AUTHENTICATION (yes). See pepsi-stage-vks-confirm(1).

51.5. State

  • Inputs: state.auth.spf / state.auth.dmarc, the envelope sender and the message body.

  • Outputs: none. The stage never writes to state and never rewrites the message; what it changes is the key store’s publication bookkeeping.

51.6. See also

Key management, pepsi-keys, pepsi-httpd, pepsi-keydisc, pepsi-stage-vks-confirm(1).