SEC2-008: PUT /captures/{id}/rendering still hands a captures-only token a capture's address, company, location and source (#761 incomplete) #950
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#950
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 on 2026-10-16 in a read-only security review of
postuloat56fc9d531, checked by a second, independent pass.Severity: Low · Category: Authentication/Authorization · Reference: CWE-285 (Improper Authorization); OWASP A01:2021 (Broken Access Control)
Location:
src/postulo/api/api.py:774-803src/postulo/api/api.py:395-409(_as_output)src/postulo/api/api.py:412-425(_as_listed, the narrowed shape)Issue
#761 narrowed
GET /capturesso that a token holding onlycapturessees the title, datesand review link and not the address, company, location or source of the queue (
_as_listedblanks them). The rendering call answers with the unnarrowed row, on both its branches:
Where both the instance and the account keep renderings (both off by default), a
captures-only token can send a small valid picture to each pending capture whose id it learns
from the list and receive
url,company_name,locationandsourcefor each in the 201;sending the same bytes again returns the full row in the 200 as well. The capture's one
rendering slot is spent on that picture, which also stops the browser's real rendering being
kept, so the probe leaves a trace; it still reads what #761 said this scope should not.
Impact
Somebody holding a leaked browser-extension token, on an instance and account where kept
renderings are switched on, reads the company and location of every posting the person is
currently considering, which the threat model says this token is never told.
Fix
Answer
attach_renderingwith_as_listed(request, capture)instead of_as_output(...)atapi.py:803; the singlereturncovers both the 200 and the 201 (the 201 ofPOST /capturesmay stay whole: it describes the capture the caller just sent). Done when a case in
tests/test_hardening_761.py(ortests/security/test_captured_pages.py) sends a renderingwith a captures-only token and asserts
url,company_name,locationandsourcecomeback empty, and whole with a token that also holds
read.Related
#761 (closed) - the same weakness on
GET /captures; the fix did not reach thePUTanswer,so this is the incomplete half of it. #803 and #536 (closed) - the sibling oracle on
/captures/known, a different route.