[pentest2] Password-protected pastes: unauthenticated password guessing via GET query params bypasses rate limiting #81

Closed
opened 2026-09-09 15:40:04 +00:00 by poslop · 2 comments
Owner

Severity: High
Target: palette-dev v0.2.1 (10.0.1.47, Host: palette-dev.archfox.org)

The password check accepts the password via URL query string (?password=) on both /api/pastes/{id} and /{id}//raw/{id}. This path performs no rate limiting at all, unlike the POST password form (rate-limited ~5 attempts/burst, keyed per paste).

Repro (verified):

# 200 rapid guesses via GET -> zero 429s, 4.5s elapsed
curl -sk -H 'Host: palette-dev.archfox.org' 'https://10.0.1.47/api/pastes/<id>?password=bruteN'
# contrast: POST /{id} with form password -> 429 after ~5 attempts

Full proof-of-concept: a 4-digit PIN-protected paste was cracked by exhaustive search (10k attempts, ~95 s, no throttling):

  • created paste with password: "4321"; brute-forced via GET query; recovered 4321 and read full content.

Fix: rate-limit password verification per paste regardless of transport (query/form), or drop query-string password support entirely (also avoids password leaking into access logs/Referer).

**Severity:** High **Target:** palette-dev v0.2.1 (10.0.1.47, Host: palette-dev.archfox.org) The password check accepts the password via URL query string (`?password=`) on both `/api/pastes/{id}` and `/{id}`/`/raw/{id}`. This path performs **no rate limiting at all**, unlike the POST password form (rate-limited ~5 attempts/burst, keyed per paste). Repro (verified): ``` # 200 rapid guesses via GET -> zero 429s, 4.5s elapsed curl -sk -H 'Host: palette-dev.archfox.org' 'https://10.0.1.47/api/pastes/<id>?password=bruteN' # contrast: POST /{id} with form password -> 429 after ~5 attempts ``` Full proof-of-concept: a 4-digit PIN-protected paste was cracked by exhaustive search (10k attempts, ~95 s, no throttling): - created paste with `password: "4321"`; brute-forced via GET query; recovered `4321` and read full content. Fix: rate-limit password verification per paste regardless of transport (query/form), or drop query-string password support entirely (also avoids password leaking into access logs/Referer).
Author
Owner

Confirmed live on v0.2.1 dev: 8 consecutive wrong passwords via GET ?password= all returned 401 with zero 429s, then the correct password succeeded. The POST form path rate limits but the API GET path does not. Fix: apply the same per-IP+per-paste unlock rate limiter to ALL password checks regardless of transport (header, query, or form).

Confirmed live on v0.2.1 dev: 8 consecutive wrong passwords via GET `?password=` all returned 401 with zero 429s, then the correct password succeeded. The POST form path rate limits but the API GET path does not. Fix: apply the same per-IP+per-paste unlock rate limiter to ALL password checks regardless of transport (header, query, or form).
poslop added spent time 25 seconds 2026-09-09 15:58:36 +00:00
Author
Owner

Fixed and merged to main (v0.2.2 pending release).

Fixed and merged to main (v0.2.2 pending release).
Sign in to join this conversation.
1 Participants
Notifications
Total Time Spent: 25 seconds
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: poslop/palette#81