fix(security): rate-limit share-link password verification (TASK-2055)#913
Merged
Merged
Conversation
Share-link password verification had no dedicated brute-force limiter, so a
password-protected /s/{token} link could be ground offline-fast — the resolve
handler would bcrypt-compare an unbounded stream of guesses.
Add two limiters, both charged BEFORE the bcrypt compare:
- SharePasswordIP (5 / 10-per-hour, keyed on SHA-256(share ID)+client IP)
caps a single grinder and protects bcrypt CPU; per-IP so one caller can't
lock out other viewers, and it's checked first so a single address can't
drain the link-wide bucket.
- SharePasswordShare (60 / 60-per-hour, keyed on SHA-256(share ID)) caps the
aggregate guess rate across a botnet that rotates IPs. Charged pre-compare
like login's per-email AuthEmail gate, so an exhausted link blocks even a
would-be-correct guess (no password oracle). Its burst is sized so ordinary
multi-viewer traffic never trips it, and the per-IP gate ahead of it means
exhausting it needs a genuine botnet (self-healing) — the same bounded
tradeoff AuthEmail accepts for an unauthenticated shared secret.
Both keyed on SHA-256 so no secret hits the limiter map.
Claude-Session: https://claude.ai/code/session_015yuBJQYfDj95cgX3DaD8SF
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.
TASK-2055 — Brute-force limiter for share-link password verification
Share-link password verification (
GET /api/v1/s/{token}withX-Share-Password) had no dedicated brute-force limiter, so a password-protected link could be ground fast — the resolve handler would bcrypt-compare an unbounded stream of guesses.Fix
Two limiters in
RateLimiters, both charged before the bcrypt compare inhandleResolveShareLink:SharePasswordIP— 5 guesses / 10-per-hour, keyed onSHA-256(share ID)+client IP. Caps a single grinder and protects bcrypt CPU. Per-IP, so one caller can't lock out other viewers; checked first so a single address can't drain the link-wide bucket.SharePasswordShare— 60 guesses / 60-per-hour, keyed onSHA-256(share ID). Caps the aggregate guess rate across a botnet that rotates IPs. Charged pre-compare like login's per-emailAuthEmailgate, so an exhausted link blocks even a would-be-correct guess (no password oracle). Burst sized so ordinary multi-viewer traffic never trips it; the per-IP gate ahead of it means exhausting it needs a genuine botnet (self-healing) — the same bounded tradeoffAuthEmailaccepts for an unauthenticated shared secret.Both keyed on SHA-256 so no secret hits the limiter map. In-memory limiter — no DB migration.
Tests
internal/server/handlers_share_links_bruteforce_test.go:Gates
go build,go test ./...,golangci-lintoninternal/server— all green. Self-Codex review: CLEAN.https://claude.ai/code/session_015yuBJQYfDj95cgX3DaD8SF