Checking a portfolio link follows a redirect onto a private address, and reports what it found #57
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
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#57
Loading…
Add table
Add a link
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?
What happens
resume/links.pyvalidates the address a person saved, and then makes the request with aplain client that follows redirects on its own:
Nothing checks where a redirect goes. A public host answering
302 Location: http://127.0.0.1:9000/sends the request there, and the status that comes back is writtenonto the link and shown in the interface.
Demonstrated against the real code with a mock transport, pressing Check on a link at a
public host that redirects inwards:
The same redirect through the logo fetcher, which uses the guarded client, is refused:
Why it matters
Postulo is self-hosted, which usually means it sits beside a router's administration page,
a NAS, a hypervisor and whatever else is on that network. This turns Check into a port
scanner for that network whose results are displayed: "Answered 200" and "Answered 401"
distinguish a service that exists from one that does not, and a
GETfollows theHEADwhenever the first answer is 401, 403, 405, 501 or a 5xx — so it is not even limited to
requests without side effects.
Only somebody who can sign in can reach it, which is the one thing keeping this from being
worse. On a multi-person instance, every account holder has it.
The file says otherwise
The module docstring already states the intended behaviour:
The design was right and the code does not do it. That is the whole bug.
Fix
Use
postulo.plugins.http.client(). It attachescheck_destinationas a request eventhook, so every request the client makes is checked, redirects included — which is
exactly why it exists, and why the logo fetcher is not affected.
Then a test with a mock transport that redirects to a private address, asserting the
request is never made — the same shape as the one that demonstrated this.
Classification
Bug, security. Not breaking.