Skip to content

Refuse redirects when fetching a key, and read a naive now as UTC - #5

Merged
jwrosewell merged 1 commit into
mainfrom
fix/refuse-redirects
Sep 6, 2026
Merged

Refuse redirects when fetching a key, and read a naive now as UTC#5
jwrosewell merged 1 commit into
mainfrom
fix/refuse-redirects

Conversation

@jwrosewell

Copy link
Copy Markdown
Contributor

Found in review after the fetch was merged.

The fetch followed redirects. urllib follows a redirect to any host and
to any of http, https or ftp, so a creator whose domain answered 302 to
some other place, or to plain http, would have that other place's key
trusted as its own, and a network attacker able to bend the creator's
DNS, or a creator that was simply misconfigured, could put a key there
and have forgeries verify. The Java port refuses a change of protocol,
so the Python port was the weaker of the two. The default transport now
uses an opener whose redirect handler refuses every redirect, so the 3xx
comes back as the response code and the caller reads the key as
unavailable, which is what it is. The stand in end point learned to
answer with a redirect to another host, and the test proves the key is
not fetched from there. The test fails when redirects are followed
again.

public_key_url now checks the scheme where the URL is built, not only
before the request, so a caller who only wants the URL cannot be handed
one whose scheme is really a prefix naming some other host.

public_key_response_at raised TypeError when given a naive datetime as
now, because it compared it with an aware date, while the schedule reads
a naive datetime as UTC. The two now agree.

The README's fetch example asked a real resolver for creator.invalid and
asserted the answer. RFC 6761 only says resolvers should refuse the
name, and under a TLS intercepting proxy the answer is a block page,
which reads as an unreadable key rather than an unavailable one and
fails the README test. The example now passes a transport that refuses,
so it shows the same shape and makes no request.

Added the two pass check that tells selecting by start from anything
else: the genuine identifier verifies under the published schedule and
reads as not matching when every start is moved a week later.

163 tests, up from 161.

Produced with AI assistance after an adversarial review of #4, and needs human review before merging. Both fixes were proved by mutation: the redirect test fails when redirects are followed again.

Found in review after the fetch was merged.

The fetch followed redirects. urllib follows a redirect to any host and
to any of http, https or ftp, so a creator whose domain answered 302 to
some other place, or to plain http, would have that other place's key
trusted as its own, and a network attacker able to bend the creator's
DNS, or a creator that was simply misconfigured, could put a key there
and have forgeries verify. The Java port refuses a change of protocol,
so the Python port was the weaker of the two. The default transport now
uses an opener whose redirect handler refuses every redirect, so the 3xx
comes back as the response code and the caller reads the key as
unavailable, which is what it is. The stand in end point learned to
answer with a redirect to another host, and the test proves the key is
not fetched from there. The test fails when redirects are followed
again.

public_key_url now checks the scheme where the URL is built, not only
before the request, so a caller who only wants the URL cannot be handed
one whose scheme is really a prefix naming some other host.

public_key_response_at raised TypeError when given a naive datetime as
now, because it compared it with an aware date, while the schedule reads
a naive datetime as UTC. The two now agree.

The README's fetch example asked a real resolver for creator.invalid and
asserted the answer. RFC 6761 only says resolvers should refuse the
name, and under a TLS intercepting proxy the answer is a block page,
which reads as an unreadable key rather than an unavailable one and
fails the README test. The example now passes a transport that refuses,
so it shows the same shape and makes no request.

Added the two pass check that tells selecting by start from anything
else: the genuine identifier verifies under the published schedule and
reads as not matching when every start is moved a week later.

163 tests, up from 161.
@jwrosewell
jwrosewell merged commit 740c59c into main Sep 6, 2026
2 checks passed
@jwrosewell
jwrosewell deleted the fix/refuse-redirects branch September 6, 2026 15:44
Automation51D pushed a commit to 51Degrees/pipeline-python that referenced this pull request Sep 6, 2026
…-python to the commit that refuses redirects when fetching a key'

The 51Degrees fork of owid-python now carries SWAN-community/owid-python#5,
which stops the fetch following a redirect from a creator domain, so a
creator whose domain answered 302 could no longer have some other host's
key trusted as its own. It also reads a naive now as UTC on the creator
side and makes the README example run without a network. The pin moves
from 5fe9a7cc to 740c59ca, the fork's main after the sync, and the build
time copy into the package picks the new source up unchanged.

fiftyone_pipeline_did tests: 145 passed, 2 skipped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant