Widen AP signature freshness window from 30s to a few minutes #102
Labels
No labels
bug
duplicate
enhancement
future
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/TeaLeaves#102
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Severity: Low · Confidence: Medium · Effort: XS · Category: code
Evidence
api/src/lib/apCrypto.ts:198,244-Math.abs(Date.now() - reqTime) > 30_000.Problem
The 30-second
datefreshness window is far tighter than the fediverse norm (Mastodon et al. allow ~1-12 h). Legitimate peers with >30s clock drift (no NTP guarantee) are silently rejected as invalid signatures. Signature verification is otherwise well-built (covers(request-target),date,digest; verifies digest against rawBody; binds keyId?actor on the entry path).Impact
Intermittent, hard-to-diagnose federation failures with well-behaved but slightly-skewed peers.
Fix
Widen to ~300s, keeping replay protection meaningful.
Acceptance criteria
Filed from the 2026-07-15 codebase audit. Full report:
docs/.internal/report-2026-07-15.md(gitignored).Fixed in
c1ed843(v7.2.0 wave 2).Extracted
SIGNATURE_FRESHNESS_MS = 300_000inapCrypto.tsand applied it to both verifiers.Worth noting: the issue cites lines 198 and 244, and the second one nearly got missed —
verifyGetSignaturereturnsnullrather thanfalse, so a naive replace of theverifyInboxSignatureline leaves the GET path (signed reads of a host project, #62) still on 30s. Both are now on the shared constant; grepping for30_000in that file returns nothing.Acceptance criteria:
±60s), since a peer can be ahead of our clock as easily as behind.I also had to retarget the existing replay test: it used a date exactly
5 * 60_000old, which against a 300_000 ms window would have been decided by however many milliseconds elapsed between constructing the date and evaluating the comparison — a coin-flip. It now uses 1 hour, matching this issue's acceptance criteria.Replay protection remains meaningful: the digest is still verified against the raw body unconditionally, and
(request-target)/date/digestmust all be signed, so a captured signature is only reusable verbatim within 5 minutes.CI green (242/242).