Conversation
Adds a new internal/safetext package and applies it across SMTP, IMAP,
and CLI output to address a set of vulnerabilities discovered in a
broad security audit of the codebase:
- SMTP header injection (HIGH): Subject, In-Reply-To, References,
From/To/Cc derived from received emails could carry CR/LF and inject
arbitrary headers (e.g., Bcc) when replying or forwarding. Subject in
particular bypassed RFC 2047 encoding when the value was pure ASCII.
All header values now go through SanitizeHeaderValue, which strips
CR/LF before they reach the DATA stream. Envelope addresses (MAIL
FROM / RCPT TO) are now rejected outright if they contain CR/LF.
- TLS misconfiguration (MEDIUM): IMAP and SMTP clients use
InsecureSkipVerify because Proton Bridge presents a self-signed cert
on localhost. The localhost trust assumption was never enforced — a
tampered config file or a --config redirect to a remote host would
ship the Bridge password to an attacker over a TLS channel with no
cert verification. Connect/Send now refuse to dial anything that is
not a loopback address.
- Latent shell injection in mail watch --exec (MEDIUM): the exec
template is passed to `sh -c`, with `{}` substituted for a numeric
sequence number. This is currently safe because only a uint32 is
interpolated, but extending the template to email-derived data would
make it RCE. Email metadata is now exposed via environment variables
(PM_MSG_SEQ, PM_MSG_UID, PM_MSG_FROM, PM_MSG_SUBJECT) so users have a
safe way to reference it without string substitution.
- ANSI escape injection in terminal output (MEDIUM): email Subject,
From, body, attachment filename, and content type are printed
verbatim to stdout in mail list/read/search/watch/thread. An
attacker email can embed ANSI/OSC escape sequences to obscure
output, spoof terminal hyperlinks (OSC 8), or manipulate the
terminal clipboard (OSC 52). All email-derived text-mode prints now
go through SanitizeForTerminal. JSON output is unchanged.
Also bumps version to 0.2.5 and documents the new env vars in
docs/commands.md for `mail watch --exec`.
`bd init` adds export-state/ to .beads/.gitignore and appends a session-completion checklist to AGENTS.md. No code change.
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.
Summary
Broad security audit of the codebase surfaced four classes of newly-introduced (concrete) vulnerabilities outside the path-traversal fix in v0.2.3. This PR ships a new
internal/safetextpackage and applies it across SMTP, IMAP, and CLI output to close them.Message-ID(copied intoIn-Reply-To/References) andSubject(ASCII CRLF bypassed RFC 2047 encoding)safetext.SanitizeHeaderValuebefore reaching the DATA stream. Envelope addresses (MAIL FROM/RCPT TO) are rejected outright if they contain CR/LF.InsecureSkipVerify: truefor IMAP+SMTP without enforcing the localhost trust assumption — a tampered config or--configredirect would ship the Bridge password to a remote hostConnect()andSend()refuse to dial anything that's not a loopback address.mail watch --execpasses the template tosh -c. Currently safe (only numericSeqNumin{}) but latent RCE if extended to email-derived dataPM_MSG_SEQ,PM_MSG_UID,PM_MSG_FROM,PM_MSG_SUBJECT) so users have a safe path forward without string substitution.safetext.SanitizeForTerminal. JSON output unchanged.Bumps version to 0.2.5.
Files changed
internal/safetext/— new package withSanitizeHeaderValueandSanitizeForTerminalplus testsinternal/smtp/client.go— header sanitization inwriteMessage, loopback check inSend, CR/LF rejection on envelope addressesinternal/imap/client.go— loopback check inConnect, header sanitization inbuildDraftMessageinternal/cli/mail.go— terminal sanitization on every email-derived text print sink (list, read, search, watch, thread, attachment download); env-var injection in watch--execinternal/cli/cli.go— version bump to 0.2.5docs/commands.md— document new env vars formail watch --execTest plan
go test ./...— full suite passes (new tests:safetext, IMAP loopback rejection, draft header injection; SMTP loopback rejection, header injection, address-list sanitization)go vet ./...cleangofmt -lcleanpm-cli versionreports0.2.5--exec)What this PR explicitly does NOT change
The audit also surfaced four LOW-severity findings (template YAML pre-parse substitution, password-in-Go-string lifetime,
--outaccepting arbitrary paths in agent contexts,htmlToTexthref URL filtering). All four are defense-in-depth rather than concrete exploits and are tracked as separate follow-up issues.