Drop duplicate rate-limits page, link API.md to Security Notes rate-limiting section (#144)

fen
2026-09-10 11:13:34 -05:00
parent f449215bf9
commit bb7632fd4d
2 changed files with 1 additions and 19 deletions
+1 -1
@@ -43,7 +43,7 @@ machine-readable `code` the web UI maps to plain-language guidance (#105):
| `slug_reserved` | 400 | custom slug is reserved | | `slug_reserved` | 400 | custom slug is reserved |
| `expiry_invalid` | 400 | expires_in out of 1 minute 1 year range | | `expiry_invalid` | 400 | expires_in out of 1 minute 1 year range |
| `content_too_large` | 413 | content or body exceeds the size cap | | `content_too_large` | 413 | content or body exceeds the size cap |
| `rate_limited` | 429 | too many requests; see `Retry-After` | | `rate_limited` | 429 | too many requests; see `Retry-After`; see [Security Notes](security.md) for limiter details |
Other statuses: `400` invalid body, `401` password required, `404` paste Other statuses: `400` invalid body, `401` password required, `404` paste
expired/burned/gone. Unknown codes should be treated as a generic failure. expired/burned/gone. Unknown codes should be treated as a generic failure.
-18
@@ -1,18 +0,0 @@
# Rate Limits
Palette rate limits paste creation per client IP: burst of 5, then 1 request per second. Exceeding it returns `429` with a `Retry-After` header (see [API](API.md)).
## Client IP resolution
`clientIP` takes the **rightmost** entry in `X-Forwarded-For`, i.e. the address added by the trusted reverse proxy in front of Palette. This means spoofed forwarding headers cannot bypass or poison the rate-limit bucket.
Verified against palette-dev (2026-09-09, issue #144):
1. Six rapid `POST /api/pastes` from one IP: `201` x5, then `429`.
2. Repeated while sending spoofed headers `X-Forwarded-For: 1.2.3.4`, `X-Real-Ip: 9.9.9.9`, `True-Client-Ip: 3.3.3.3`: all requests still received `429`. No bypass, and the spoofed values did not shift the bucket.
## Known tradeoff: shared egress IPs
Because the bucket is keyed solely by client IP, everyone behind one egress IP (office network, VPN, carrier NAT) shares a single burst-5 / 1rps create budget. One heavy user can rate-limit everyone behind that IP.
This is an inherent property of IP-keyed limiting without accounts, accepted for now. If it becomes a real problem, candidate mitigations include raising the create budget or adding per-session (cookie) buckets on top of the IP bucket.