Skip to content

Restrict refresh_remote to bounded HTTP(S) fetches#265

Merged
seanwevans merged 1 commit into
mainfrom
claude/remote-policy-fetch-hardening
Jul 20, 2026
Merged

Restrict refresh_remote to bounded HTTP(S) fetches#265
seanwevans merged 1 commit into
mainfrom
claude/remote-policy-fetch-hardening

Conversation

@seanwevans

Copy link
Copy Markdown
Owner

Issue

policy.refresh_remote is documented (API.md) as fetching policy YAML over HTTP, but it passed the caller-supplied URL straight to urllib.request.urlopen and read the response with an unbounded fh.read():

  • urllib accepts file:// and ftp:// URLs, so a mis-plumbed URL silently turns the policy fetch into a local-file read primitive.
  • A hostile or misbehaving policy server can stream an arbitrarily large response, which is buffered in full before any schema validation runs.

Fix

  • Reject any URL whose scheme is not http/https with a ValueError before opening the connection.
  • Cap the response body at _MAX_REMOTE_POLICY_BYTES (1 MiB — generous for YAML policy documents) and raise ValueError when exceeded.

Existing behavior is otherwise unchanged: timeout retries, temp-file handling, and the refresh() pipeline are untouched.

Testing

  • New test_refresh_remote_rejects_non_http_scheme (a file:// URL raises before any fetch) and test_refresh_remote_rejects_oversized_response (a local HTTP server serving 1 MiB + 1 gets rejected).
  • Full suite: 411 passed, 2 environment-gated skips; all pre-commit hooks (isort, black, pylint, flake8, mypy) pass.

Note: while adding these tests I found that tests/test_remote_policy.py fails when run as a standalone file on current main — two pre-existing tests depend on an earlier test file leaving the global policy token set. That's unrelated to this change; fix coming in a separate PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DDSofWX5HwawsrwbN2nSXR


Generated by Claude Code

refresh_remote passed the caller URL straight to urllib and buffered the
whole response, so a file:// or ftp:// URL was silently accepted and a
hostile/misbehaving policy server could stream unbounded data into
memory before validation. Reject non-HTTP(S) schemes up front and cap
the response body at 1 MiB.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDSofWX5HwawsrwbN2nSXR
@seanwevans
seanwevans merged commit 2238935 into main Jul 20, 2026
19 checks passed
@seanwevans
seanwevans deleted the claude/remote-policy-fetch-hardening branch July 20, 2026 20:53
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.

2 participants