security: document rate limiter IP-keying, anti-spoofing verification, shared-bucket tradeoff (#144)
+21
@@ -0,0 +1,21 @@
|
|||||||
|
# Security Notes
|
||||||
|
|
||||||
|
Notes from the exploratory security pass on palette-dev (2026-09-09). No issues remain open from these findings; this page records the verified behavior and known tradeoffs.
|
||||||
|
|
||||||
|
## Rate limiting
|
||||||
|
|
||||||
|
### Bucket key and header spoofing (verified, #144)
|
||||||
|
|
||||||
|
The create rate limiter is keyed on `clientIP`, which takes the **rightmost** entry in `X-Forwarded-For` (the address of the immediate peer as seen by the trusted proxy layer). This means:
|
||||||
|
|
||||||
|
- Spoofed `X-Forwarded-For`, `X-Real-Ip`, and `True-Client-Ip` headers **cannot bypass or poison the bucket**.
|
||||||
|
- Verified on palette-dev: six rapid `POST /api/pastes` from one IP gave 201 x5 then 429; repeating while sending `X-Forwarded-For: 1.2.3.4`, `X-Real-Ip: 9.9.9.9`, and `True-Client-Ip: 3.3.3.3` still returned 429 for every request (no bypass).
|
||||||
|
|
||||||
|
### Create budget
|
||||||
|
|
||||||
|
- Budget per IP: **burst of 5** creates, refilled at **1 request/second**.
|
||||||
|
- Sixth rapid create from the same IP gets `429 Too Many Requests`.
|
||||||
|
|
||||||
|
### Known inherent limitation: shared egress IP
|
||||||
|
|
||||||
|
The limiter is keyed solely by IP, so clients behind a single egress address — an office NAT, a VPN exit node, a CGNAT carrier — share **one** create bucket. One heavy user can consume the burst-5 budget and cause `429` responses for everyone behind that IP. This is an inherent tradeoff of IP-keyed limiting, accepted for now; alternatives (auth-scoped or cookie-scoped buckets) would be a design change and have not been scheduled.
|
||||||
Reference in New Issue
Block a user