fetchtron
A safe HTTP GET with the guardrails most clients leave to you.
One call fetches a URL and contains it: a deny-by-default domain allowlist, SSRF
protection, robots.txt (RFC 9309), and hard caps on size, time and redirects — with the
allowlist and SSRF checks re-run on every redirect hop, so a 302 cannot walk the
request to an internal address or an off-list host.
from fetchtron import fetch, FetchError
try:
got = fetch("https://example.org/doc", allowlist=["example.org"])
except FetchError as e:
print(e.code) # blocked_by_allowlist | blocked_private_address | robots_disallowed | ...
else:
print(got.final_url, got.status, got.content_type, len(got.content))
print(got.text) # decoded best-effort; got.content is the raw bytes
Or from the shell (deny-by-default: at least one --allow is required):
$ fetchtron get https://example.org/doc --allow example.org --json
What it guards
| Guard | Behaviour |
|---|---|
| Allowlist | deny-by-default; a domain also covers its subdomains; re-checked every redirect hop |
| SSRF | refuses loopback, private, link-local (incl. 169.254.169.254 cloud metadata), reserved, multicast and unspecified addresses |
| robots.txt | RFC 9309: 4xx = no rules (allowed); 5xx or unreachable = disallowed |
| Caps | max_bytes (streamed, never the whole page in memory), timeout_s (total), max_redirects |
| Scheme | http/https with a host only |
| Provenance | cleaned url/final_url (no credentials, no fragment), status, content_type, content_hash |
The allowlist is data you pass in — where the policy comes from (a config file, a
per-tenant rule, an area map) is your business; fetchtron only enforces it. It is
content-agnostic: pass content_types=["text/html"] to restrict, or omit it for any.
Why it exists
The classic SSRF bug is a plain requests.get(url) that follows a redirect to
http://169.254.169.254/… or http://10.0.0.5/…. Raw clients give you none of this
containment; you are expected to bolt it on, and most code doesn't. fetchtron is that
containment in one call, on a maintained client.
How it compares
See POSITIONING.md for the evidence-based comparison with raw requests/httpx,
advocate, and the web tools in langchain/smolagents — including the one place a
competitor did better (DNS-rebinding) until 0.2.0, which pins the checked IP into the
connection.
Install
pip install fetchtron
MIT licensed. Part of the network-agents-setup ecosystem; extracted from its governed runner so any project can fetch the web safely.
Metadata
Release files for fetchtron 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| fetchtron-0.2.0.tar.gz | 14.1 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fetchtron-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.4 kB
Release files / fetchtron-0.2.0.tar.gz
| Download URL | fetchtron-0.2.0.tar.gz |
|---|---|
| Size | 14.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5b842cd9b8fbbfaa6ff020758062c3f2d9de66085212247c03e8ec252cddf8be
|
|
BLAKE2b-256 checksum How to use checksums |
c35436e01b22abacbbd7b72ebde16aa1cc0910dcb6af3dceea699aac5273a6f7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / fetchtron-0.2.0-py3-none-any.whl
| Download URL | fetchtron-0.2.0-py3-none-any.whl |
|---|---|
| Size | 11.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b9008bd0b65aadbc8c46bbb02a7cefb08ecc2a8c3ecaf3760498e2f0c1fb7504
|
|
BLAKE2b-256 checksum How to use checksums |
3807207d6b8846ced5f1210f813d5850746ee09f5faff00f9e1bc1490d41e547
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logSecurity for fetchtron 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for fetchtron-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.