PST-032: A captures-only token reads the whole pending review queue, including company, location and URL of every capture #761
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#761
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found in the security audit of 2026-10-10 (
SECURITY-AUDIT-2026-10-10.md), run againstmainatc30851bfrom 8 to 10 October 2026, as PST-032. Severity: Low.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.
src/postulo/api/api.py(650-680)Who can do it, and what they need. Someone holding a leaked browser-extension token (scope
capturesonly). Precondition: the token, which the threat model treats as the least trusted credential Postulo issues.How it works.
GET /api/v1/captureswith the captures-only token.title,company_name,location,url,review_urlandpagedetails. Verified: a capture created with origin='web' and data {company_name:'Hush Corp', location:'Lisbon'} came back in full to a captures-only token.Impact. The threat model states a leaked extension token can 'fill a review queue' and, when asking whether a posting is held, is told 'the title, the date and a link, never the company, the address or where the person stands with it'. The list endpoint hands over the company and location of every posting the person is currently considering, which is a picture of their job search. Limited scope (pending captures only), hence medium at most; may be judged intended since the operation is documented under the scope.
Evidence.
Verification (verdict: confirmed; severity after verification: Low; first-pass claim: Medium). File and lines are right (api.py 647-677, CaptureOut 353-365, _as_output 392-406). Correct the framing: this is a documented and tested operation of the
capturesscope, so the fix is a policy decision. Either return only title/date/link for a captures-only token, as POST /captures/known does, or amend the threat-model row and the scope label to say the token can read the pending queue including company and location. It is not cross-account (for_user() is applied) and shows only pending captures. Precondition: a leaked extension token plus the instance URL.Suggested remediation. Either narrow
GET /capturesfor a captures-only token to the fieldsKnownCaptureOutalready limits to (id, title, created_at, review_url), returning the full shape only to a token that also holdsread; or move the list underreadand update the threat model/wiki to say what a captures token can see.Fixed in
3aa2b8f53on main.