Federation: reject stale and incomplete HTTP signatures #8033
No reviewers
Labels
No labels
AP C2S
AdminAPI
Breaking API
Breaks existing config
Check if still valid
Data Protection
Do not merge
Document in the changelog
Doing
Feature Request / Enhancement
MastoAPI
NL2
NL4
OStatus
OTP Releases
Refactor
Security
To Do
TwitterAPI
bug
complicated
confirmed
deps
discussion
documentation
easy
feature: to be merged in stable
fix: to be merged in stable
incident
needs to be backported to maint
needs-changes
needs-info
needs-review
performance
regression
unclear
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
pleroma/pleroma!8033
Loading…
Reference in a new issue
No description provided.
Delete branch "lambadalambda/pleroma:fix/signature-freshness"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Incoming HTTP signatures were checked only cryptographically. A captured signed GET could be replayed forever (defeating authorized fetch), and a signed POST that did not cover
digestvalidated with any body.New checks before the signature is verified (cavage signatures):
dateor(created)must be signed, and the signed time must be withinsignature_max_age(default 2 h, like Akkoma) andsignature_max_clock_skew(default 1 h, like Mastodon).digest, and the body must have been hashed by DigestPlug.Dateheader (a second, freshDateheader could otherwise hide an old signed one).Failing GETs count as unsigned; failing inbox POSTs get 401 and are not queued (the signature retry worker only re-checks the cryptography).
config :pleroma, :activitypub, signature_policy: :logonly logs instead. Mastodon already enforces stricter rules (5 min + 1 h skew), so every sender that federates with Mastodon passes. Pleroma's own publisher and fetcher requests are tested end to end against the new checks.Based on Akkoma's http_signatures changes.
Decision:
:enforcestays the default./oc review
opencode-agent:job=133:generation=1
Review of the complete base-to-head diff plus surrounding code (plug pipeline, DigestPlug, inbox controller, publisher/fetcher signing, retry worker, http_signatures 0.1.3 split_signature/validate semantics).
No findings. The new check_signature_policy runs before cryptographic verification and is fail-closed in every mismatch I could construct:
Merge-readiness: 5/5 - production-ready, no known findings.
/oc review
opencode-agent:job=139:generation=1
Review of the complete base-to-head diff and the surrounding enforcement path (HTTPSignaturePlug, DigestPlug body_reader, inbox controller, publisher/fetcher signing, SignatureRetryWorker, http_signatures 0.1.3 signature parsing/validation).
No findings. The new check runs before cryptographic verification and is fail-closed in every gap I could construct:
dateor(created)must be signed, and the value the window check reads is exactly the value the crypto check verifies: duplicateDateheaders are rejected outright, so the library's last-wins header-map collapse can never diverge from the checked value. A missing or unparsable date fails closed, as does the cavagedatedefault when noheadersparameter is present.digest, and the digest the crypto check verifies is the DigestPlug-computed hash of the received body (assigns[:digest]is required, so an unhashed body cannot pass; the computed digest replaces the header before both checks run).(created)is still rejected end to end: the signature library itself only accepts(created)timestamps at or before now, so the policy's skew window for(created)cannot admit a future timestamp past the cryptographic check.:logmode explicitly downgrades violations to a warning.date) and(created)cases.I also ran the touched suites against this head: signature tests (26 tests), plug policy plus plug tests (12), inbox controller tests (137), plug MRF test (1) — all pass.
Merge-readiness: 5/5 - production-ready, no known findings.