Compile an untrusted public URL into a bounded, verifiable context artifact
Project description
FetchSeal
Fetch public HTTP(S) resources under a strict network policy and turn them into verifiable, citation-ready artifacts. Remote content remains untrusted data.
Alpha: FetchSeal is pre-release software published on PyPI. Expect API changes before 1.0.
Install
FetchSeal requires Python 3.11 or newer; CI tests Python 3.11–3.14. Install the base package from PyPI:
python -m pip install fetchseal
For the v0.1.0a3 GitHub prerelease, download and verify the attested wheel
before installing it:
gh release download v0.1.0a3 --repo ShiroKSH/fetchseal --pattern "*.whl"
gh attestation verify fetchseal-0.1.0a3-py3-none-any.whl --repo ShiroKSH/fetchseal
python -m pip install fetchseal-0.1.0a3-py3-none-any.whl
The project has no core runtime dependencies. The optional MCP adapter is separate. It applies stricter extraction limits and rejects serialized artifact payloads larger than 4 MiB:
python -m pip install "fetchseal[mcp]"
CLI
fetchseal https://example.com --format json
fetchseal inspect https://example.com --format json
fetchseal https://example.com --record --cache-dir .fetchseal
fetchseal replay sha256:CAPTURE_ID --cache-dir .fetchseal
fetchseal diff artifact-before.json artifact-after.json --format json
fetchseal schema --format json
--metadata-only still downloads, bounds, decodes, and hashes the response
body; it skips only document extraction. It is not a HEAD request.
Strict defaults accept only GET/HEAD over HTTP or HTTPS to globally routable
addresses on ports 80/443. FetchSeal does not read proxy variables, .netrc,
browser cookies, or ambient authorization.
Python
from fetchseal import fetch
artifact = fetch("https://example.com")
print(artifact.content.text)
print(artifact.provenance.body_sha256)
print(artifact.sections[0].citation_id)
artifact.verify()
Sync and async clients share the same policy and transport logic:
from fetchseal import AsyncClient, Client, StrictPolicy
with Client(policy=StrictPolicy()) as client:
artifact = client.fetch("https://example.com")
async with AsyncClient(policy=StrictPolicy()) as client:
artifact = await client.fetch("https://example.com")
Artifact shape
Artifacts use versioned ContextArtifact v1 JSON. This deliberately abridged example is not a complete schema-valid artifact:
{
"schema_version": "1.0",
"content_id": "sha256:<decoded-body-hash>",
"capture_id": "sha256:<stable-capture-fingerprint>",
"trust": {
"classification": "untrusted_external_content",
"instructions_are_data": true,
"active_content_executed": false
},
"content": {
"text": "Example Domain",
"sections": [{"citation_id": "S0001-..."}],
"links": []
}
}
capture_id excludes only fetch timestamps, elapsed time, and itself. This is
an intentional stable-fingerprint contract: capture_id does not authenticate
those volatile fields or prove freshness. Canonical JSON uses UTF-8, sorted
keys, no insignificant whitespace, and no non-finite numbers. verify() checks
the full nonvolatile artifact fingerprint, body and content-ID hash consistency,
text and section hashes, citation IDs, trust constants, and schema version. The
fingerprint detects inconsistency; it is not an origin-authentication signature.
Security guarantees
Within the documented threat model, strict mode provides:
- strict absolute URL parsing, valid Unicode scalar values, a post-encoding 8,192-character ceiling, and lossless IDNA normalization: Unicode hosts are NFC-normalized, lowercased, and rejected if encode/decode changes them;
- denial of userinfo, ambiguous numeric hosts, local names, special IP ranges, cloud metadata and platform-service addresses including Azure WireServer (also through IPv4-mapped IPv6 and NAT64), and non-default ports;
- fail-closed evaluation of every DNS answer;
- a TCP connection to the selected IP, with the original host retained for HTTP Host, TLS SNI, and certificate hostname verification;
- actual socket peer comparison with the selected IP before request bytes;
- full revalidation and a fresh connection for every manual redirect;
- no TLS downgrade, proxy, credentials, cookies, HTTP/2 coalescing, JavaScript, subresource loads, external XML entities, or telemetry;
- explicit limits on resolver concurrency, time, informational responses, HTTP chunks, headers, raw/decoded bytes, decompression ratio, JSON nodes, document structure, text, Markdown, whitespace normalization, heading paths, link URLs, locators, sections, and links; oversized HTML links are rejected before URL joining;
- pre-parse JSON root/cardinality/node limits and artifact structure budgets, with redirect-chain length enforced before entry traversal;
- strict TLS EOF handling and non-expanding redaction of every query value from exported URL metadata; a query is omitted when placeholders would expand it, while the original remains only in in-memory request state;
- opt-in-only recording with process-safe, first-writer-wins content-addressed captures; record, replay, and direct body reads share one per-capture lock, cap manifest/body/artifact sizes, and verify the manifest, hashes, capture ID, content ID, artifact, and body as one binding.
Human-oriented CLI output escapes terminal controls. JSON/JSONL remains canonical for files and pipes; interactive terminal rendering escapes C1 controls with JSON-valid Unicode escapes.
These are implementation properties, not a claim that every deployment is immune to SSRF. See the security guarantees, threat model, and residual risks.
Non-goals
FetchSeal is not a crawler, browser, general HTTP client, network egress firewall, document converter, model framework, or prompt-injection antivirus. It does not make remote content trusted. Citation delimiters and trust labels are metadata for consumers, not a model security boundary.
Comparison
| Tool category | Primary job |
|---|---|
| curl / HTTPX | Transport and HTTP primitives |
| Crawl4AI / Firecrawl | Crawling, browser use, and large-scale extraction |
| Agent egress firewalls | Process or network mediation |
| FetchSeal | Embedded bounded fetch plus a portable citation-ready artifact |
The categories solve different problems. This table does not imply that other tools are unsafe.
More
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fetchseal-0.1.0a3.tar.gz.
File metadata
- Download URL: fetchseal-0.1.0a3.tar.gz
- Upload date:
- Size: 58.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6df1afbc5755d9700ab39c767ac7247fcec47c045bd9e5b02f835ef84a443003
|
|
| MD5 |
87c2a9eb402913828061654d20667958
|
|
| BLAKE2b-256 |
a16ab881e253e9143417657ff8b4a39aee4ec29b0397833492172f176fabc6c9
|
Provenance
The following attestation bundles were made for fetchseal-0.1.0a3.tar.gz:
Publisher:
release.yml on ShiroKSH/fetchseal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fetchseal-0.1.0a3.tar.gz -
Subject digest:
6df1afbc5755d9700ab39c767ac7247fcec47c045bd9e5b02f835ef84a443003 - Sigstore transparency entry: 2164792714
- Sigstore integration time:
-
Permalink:
ShiroKSH/fetchseal@44b2e1fead2cec7778d45873fb80707772f5f156 -
Branch / Tag:
refs/tags/v0.1.0a3 - Owner: https://github.com/ShiroKSH
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@44b2e1fead2cec7778d45873fb80707772f5f156 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file fetchseal-0.1.0a3-py3-none-any.whl.
File metadata
- Download URL: fetchseal-0.1.0a3-py3-none-any.whl
- Upload date:
- Size: 59.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ecf8349e5af773b4cf33bf53e42aa6f0a2fee4e6f918119c2082c24d64b4653
|
|
| MD5 |
265fa6a6bbb4fde9491047daff14fbdc
|
|
| BLAKE2b-256 |
874ead9d24c761881126ce15e4e88587adf01faecf5351695d187731c710b6cf
|
Provenance
The following attestation bundles were made for fetchseal-0.1.0a3-py3-none-any.whl:
Publisher:
release.yml on ShiroKSH/fetchseal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fetchseal-0.1.0a3-py3-none-any.whl -
Subject digest:
4ecf8349e5af773b4cf33bf53e42aa6f0a2fee4e6f918119c2082c24d64b4653 - Sigstore transparency entry: 2164792750
- Sigstore integration time:
-
Permalink:
ShiroKSH/fetchseal@44b2e1fead2cec7778d45873fb80707772f5f156 -
Branch / Tag:
refs/tags/v0.1.0a3 - Owner: https://github.com/ShiroKSH
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@44b2e1fead2cec7778d45873fb80707772f5f156 -
Trigger Event:
workflow_dispatch
-
Statement type: