Fix forgeable transport-auth verdict; add SECURITY.md (#101) - #103
Merged
Conversation
verify_transport_authentication trusted the plaintext Authentication-Results header it selected with .pop() — the bottom-most, sender-injectable header. A sender could forge `dmarc=pass` for a spoofed From: and set transport_verified = true. Security fixes: - Select the FIRST (top-most) A-R header, stamped by the closest hop (our receiving provider), not the last. - Gate on authserv-id: honor an A-R header only when its organizational domain matches the user's provider (derived from email/IMAP host, with a known-provider map so Gmail's mx.google.com is trusted; fails closed otherwise). A sender-forged A-R with an unknown authserv-id is rejected even when it is the only one present. - SPF no longer counts as From-authentication (it authenticates the envelope MAIL FROM, not the visible From:). Correctness: - DKIM alignment now uses DMARC relaxed (organizational-domain) matching, so legitimate subdomain signatures are not false negatives. Threads the derived trusted-authserv set through the inbox filter and the spam-rescue path. Adds unit tests covering the exploit, the authserv-id gate, SPF-only, relaxed alignment, header selection, and fail-closed behavior. Adds SECURITY.md documenting the threat model (malicious provider / header-injection adversary), the npub-rooted trust model, the three trust states, what transport-auth does and does not prove, and the planned email-ownership binding. https://claude.ai/code/session_01PyRdoum6RhwJnVyQnVrEJ3
44 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #101.
verify_transport_authenticationtrusted the plaintextAuthentication-Resultsheader it selected with.pop()— the bottom-most, sender-injectable header. A sender could forgedmarc=passfor a spoofedFrom:and settransport_verified = true.Security fixes (must-fix)
.pop()selected.authserv-id. An A-R header is honored only when its organizational domain matches the user's provider, derived from the email/IMAP host with a known-provider map (so Gmail'smx.google.comis trusted even though the mailbox isgmail.com). Fails closed for unknown authserv-ids: a sender-forged A-R is rejected even when it's the only one present (defends the "provider added no A-R" case, where selecting "first" alone is insufficient).spf=pass → verifiedbranch; SPF authenticates the envelopeMAIL FROM, not the visibleFrom:. Kept for diagnostics only.Correctness (should-fix)
From: example.com/header.d: mail.example.com) is no longer a false negative.The derived trusted-authserv set is threaded through both call sites — the inbox filter and the spam-rescue path (
should_rescue_message→move_nostr_from_folder→rescue_nostr_emails_from_spam).SECURITY.md (new)
Adds the doc requested in the issue: threat model (malicious/compromised provider + header-injection adversary), the npub-rooted trust model (self-asserted addresses; resolve
trusted npub → email, neveremail → key), the three trust states (verified/signed-but-unverified/unsigned), what transport-auth does and does not prove, and the planned SecureJoin-style email-ownership binding (with the request+response-pair caveat).Tests
10 new unit tests cover the exploit (forged bottom header ignored), the authserv-id gate (forged-only rejected), SPF-only, DMARC pass, relaxed/unaligned DKIM, header-selection skip, and fail-closed behavior.
cargo test --lib: 208 passed, 0 failedcargo test --test email_integration: 21 passedOut of scope
The optional "real cryptographic DKIM verification in Rust" item is left for a follow-up.
https://claude.ai/code/session_01PyRdoum6RhwJnVyQnVrEJ3
Generated by Claude Code