Skip to content

rate-limit: getClientIp trusts spoofable X-Forwarded-For (signup limiter bypass) #23

Description

@dylanroscover

Found during the cross-model review of #20 (both Codex and Claude, signup-security). Pre-existing / inherited — not introduced by #20.

getClientIp() returns the leftmost X-Forwarded-For value (web/lib/rateLimit.ts ~L211-216), used as the identifier in withRateLimit({ identifier: 'ip' }). Behind Railway/Cloudflare the real client IP is appended, so index 0 is attacker-controlled — a caller can rotate XFF per request to get fresh signup buckets and defeat the 10/hr cap.

Mitigated in practice by the verified-Firebase-token requirement on bootstrap, so this only relaxes the per-IP cap, not auth.

Fix: derive the client IP from a provider-owned header (CF-Connecting-IP) or parse XFF right-to-left skipping trusted proxy hops; ignore client-supplied XFF.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions