PST-067: Gravatar refresh is an unthrottled server-side fetch any account can trigger #796

Closed
opened 2026-10-10 10:56:38 +00:00 by tiagoagueda · 1 comment
Owner

Found in the security audit of 2026-10-10 (SECURITY-AUDIT-2026-10-10.md), run against main at c30851b from 8 to 10 October 2026, as PST-067. Severity: Informational.

The text below is the audit's entry, unchanged apart from links to the other issues it names. The finding was produced by automated review and checked by a second automated pass; re-check it before acting on it.


  • Severity: Informational
  • Category: missing rate limit on outbound request
  • Location: src/postulo/accounts/views.py (368-383)
  • Found by: ownership review of accounts

Who can do it, and what they need. Any signed-in account with 'Use my Gravatar' ticked.

How it works.

POST /accounts/avatar/refresh/ repeatedly; each call makes the server request https://gravatar.com/avatar/<hash>?s=1024 through plugins.http.client() and decode the response image. There is no throttle on this view (capture, number collisions and recovery links have POSTULO_*_RATE limits; this does not).

Impact. The destination is fixed to gravatar.com so there is no SSRF; the cost is one outbound request and one image decode per POST, bounded by pictures.MAX_PIXELS. Denial of service is out of the threat model's scope, so informational only.

Verification (verdict: confirmed; severity after verification: Informational). No correction to file or lines. Remediation if wanted: spend a small per-account allowance (for example one that reuses throttle.fetch) in GravatarRefreshView and in the email_changed receiver.

Suggested remediation. Reuse core.throttle with a modest per-account rate (e.g. a few per hour) and ignore a refresh when gravatar_checked_at is very recent.

Found in the security audit of 2026-10-10 (`SECURITY-AUDIT-2026-10-10.md`), run against `main` at `c30851b` from 8 to 10 October 2026, as **PST-067**. Severity: **Informational**. The text below is the audit's entry, unchanged apart from links to the other issues it names. The finding was produced by automated review and checked by a second automated pass; re-check it before acting on it. --- - **Severity:** Informational - **Category:** missing rate limit on outbound request - **Location:** `src/postulo/accounts/views.py` (368-383) - **Found by:** ownership review of accounts **Who can do it, and what they need.** Any signed-in account with 'Use my Gravatar' ticked. **How it works.** POST /accounts/avatar/refresh/ repeatedly; each call makes the server request https://gravatar.com/avatar/&lt;hash>?s=1024 through plugins.http.client() and decode the response image. There is no throttle on this view (capture, number collisions and recovery links have POSTULO_*_RATE limits; this does not). **Impact.** The destination is fixed to gravatar.com so there is no SSRF; the cost is one outbound request and one image decode per POST, bounded by pictures.MAX_PIXELS. Denial of service is out of the threat model's scope, so informational only. **Verification** (verdict: confirmed; severity after verification: Informational). No correction to file or lines. Remediation if wanted: spend a small per-account allowance (for example one that reuses throttle.fetch) in GravatarRefreshView and in the email_changed receiver. **Suggested remediation.** Reuse core.throttle with a modest per-account rate (e.g. a few per hour) and ignore a refresh when gravatar_checked_at is very recent.
tiagoagueda added this to the 1.0.0 milestone 2026-10-10 10:58:04 +00:00
Author
Owner

Fixed in 3f5964a87 on main.

Fixed in 3f5964a87 on main.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#796
No description provided.