url_jail
SSRF-safe URL validation for Rust and Python.
The Problem
Your application fetches a user-provided URL:
response = requests.get(user_url)
An attacker submits http://169.254.169.254/latest/meta-data/iam/credentials.
Result: Your AWS keys are in their inbox. Your S3 buckets are public. Your cloud bill is six figures.
This is Server-Side Request Forgery (SSRF), the vulnerability behind:
- CVE-2024-0243: LangChain RecursiveUrlLoader (CVSS 8.6)
- CVE-2025-2828: LangChain RequestsToolkit (CVSS 9.1)
- Capital One 2019 breach (100M+ records)
"I'll just block 169.254.169.254"
Attackers encode IPs in ways your blocklist won't catch:
| Attack | Your Blocklist | url_jail |
|---|---|---|
http://0x7f000001/ (hex) |
Passes | Blocked |
http://0177.0.0.1/ (octal) |
Passes | Blocked |
http://2130706433/ (decimal) |
Passes | Blocked |
http://127.1/ (short-form) |
Passes | Blocked |
http://[::ffff:127.0.0.1]/ (IPv6-mapped) |
Passes | Blocked |
http://metadata.google.internal/ |
Maybe | Blocked |
| DNS rebinding | Passes | Blocked* |
* When using get_sync() or the returned Validated.ip directly.
url_jail validates after DNS resolution. Encoding tricks don't work.
Note: This library has not undergone a formal security audit. See SECURITY.md.
The Solution
Python (recommended):
from url_jail import get_sync
body = get_sync(user_url) # Validates URL and all redirects
Python (with existing HTTP client):
from url_jail.adapters import safe_session
s = safe_session()
response = s.get(user_url) # SSRF-safe requests.Session
Rust:
use url_jail::{validate, Policy};
use reqwest::Client;
let v = validate("https://example.com/api", Policy::PublicOnly).await?;
let client = Client::builder()
.resolve(&v.host, v.to_socket_addr())
.build()?;
let response = client.get(&v.url).send().await?;
Installation
pip install url_jail
# With HTTP client adapters
pip install url_jail[requests] # or [httpx], [aiohttp], [urllib3], [all]
[dependencies]
url_jail = "0.2"
# Enable fetch() for redirect chain validation
url_jail = { version = "0.2", features = ["fetch"] }
Policies
| Policy | Allows | Blocks |
|---|---|---|
PublicOnly |
Public IPs only | Private, loopback, link-local, metadata |
AllowPrivate |
Private + public | Loopback, metadata (for internal services) |
HTTP Client Adapters (Python)
# requests
from url_jail.adapters import safe_session
s = safe_session()
response = s.get(user_url)
# httpx (sync)
from url_jail.adapters import safe_httpx_client
client = safe_httpx_client()
response = client.get(user_url)
# httpx (async)
from url_jail.adapters import safe_httpx_async_client
async with safe_httpx_async_client() as client:
response = await client.get(user_url)
# aiohttp
from url_jail.adapters import safe_aiohttp_session
async with safe_aiohttp_session() as session:
async with session.get(user_url) as response:
body = await response.text()
# urllib3
from url_jail.adapters import safe_urllib3_pool
pool = safe_urllib3_pool()
response = pool.request("GET", user_url)
Advanced: Custom Blocklist
use url_jail::{PolicyBuilder, Policy};
let policy = PolicyBuilder::new(Policy::AllowPrivate)
.block_cidr("10.0.0.0/8")
.block_host("*.internal.example.com")
.build();
Error Handling
use url_jail::{validate_sync, Policy, Error};
match validate_sync("http://127.0.0.1/", Policy::PublicOnly) {
Ok(v) => println!("Safe: {}", v.ip),
Err(e) if e.is_blocked() => {
// Security rejection (SSRF, hostname, redirect)
println!("Blocked: {}", e);
}
Err(e) if e.is_retriable() => {
// Temporary error (DNS, timeout) - retry with caution
println!("Temporary: {}", e);
}
Err(e) => println!("Error: {}", e),
}
| Method | Returns true for |
|---|---|
is_blocked() |
SsrfBlocked, HostnameBlocked, RedirectBlocked |
is_retriable() |
DnsError, Timeout, HttpError |
url() |
Extracts the URL that caused the error |
What's Blocked
- Cloud metadata endpoints (AWS, GCP, Azure, Alibaba)
- Private IPs (10.x, 172.16.x, 192.168.x) with
PublicOnly - Loopback (127.x, ::1)
- Link-local (169.254.x, fe80::)
- IP encoding tricks: octal (
0177.0.0.1), decimal (2130706433), hex (0x7f000001), short-form (127.1) - IPv4-mapped IPv6 (
::ffff:127.0.0.1)
Features
| Feature | Description |
|---|---|
fetch |
fetch() / get_sync() with redirect validation |
tracing |
Logging for validation decisions |
License
MIT OR Apache-2.0
Release files for url-jail 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
Total release size: 65.4 MB
Release files / url_jail-0.2.0-cp314-cp314-win_amd64.whl
| Download URL | url_jail-0.2.0-cp314-cp314-win_amd64.whl |
|---|---|
| Size | 2.3 MB |
| Tags | CPython 3.14 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
bd3cb7db5ed861ae1698658835cb68c3c7c2ff18b064c88f9b9a32cf7aba3b0d
|
|
BLAKE2b-256 checksum How to use checksums |
45f526f6fbba6d5de227fe03e8432b50f21c73c86533dab348332705b78d1442
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp314-cp314-musllinux_1_2_x86_64.whl
| Download URL | url_jail-0.2.0-cp314-cp314-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.14 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
63ef2306de459a15719150443861511106b720002e7f026968377651d80197f9
|
|
BLAKE2b-256 checksum How to use checksums |
460aef7e23df3d82254a46c6dacfc6de69494773644c11144e67a38fa1f8bae7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | url_jail-0.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | CPython 3.14 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
b03687bcab6b67a9f504a259dbc6021e936d7fdf5bb180656beed7c15c6b255b
|
|
BLAKE2b-256 checksum How to use checksums |
b88fd0ab1a12137e1efd0edbd27e8bed7bc8b8c26cff117b923423b272cba6bf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp314-cp314-macosx_11_0_arm64.whl
| Download URL | url_jail-0.2.0-cp314-cp314-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.14 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
1a74ea8bc497aae1ef71114ad10cf61357877179dfb16c68b89c7f5c082534b8
|
|
BLAKE2b-256 checksum How to use checksums |
15ba02056349e78b34852038e2cfe525d63c2835d27bb2d169b8b0609c53aa97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp313-cp313-win_amd64.whl
| Download URL | url_jail-0.2.0-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 2.3 MB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
eacd3abb9a9b9ef4379fe5afa5d3a3a78f5e27df35f4fbf0be407b8cb1b9725e
|
|
BLAKE2b-256 checksum How to use checksums |
ed0896c1db77557556e7f5bd7f4114dafa4546f76b2ff5d17fa25c1c95ed3b72
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl
| Download URL | url_jail-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.13 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
6c5e060efaa4877d0ee2a9b0bc8c9c30405e526c72092a9b143ca255b49cbf86
|
|
BLAKE2b-256 checksum How to use checksums |
4a6a763e7fb9236865691c3d75ced81597ddb894f78d11ebd5486b6b9dc25fdf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | url_jail-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | CPython 3.13 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
15de02b9ec8391b588507dcfc59386b2438ccb683ed58b0a36bc740dc8e5bf93
|
|
BLAKE2b-256 checksum How to use checksums |
7fdc0606bd72909037ea43dc84e7581ab4583d4ca41aaab7512b971875101f08
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp313-cp313-macosx_11_0_arm64.whl
| Download URL | url_jail-0.2.0-cp313-cp313-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.13 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
a5465e7da76d1e157edb57d7b3c7922f0465d514c749254eb2c78fc10fc99aea
|
|
BLAKE2b-256 checksum How to use checksums |
3accdff74a084b14e5406c80602183ec58876c5861d553735ac5adc7d4c301ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp312-cp312-win_amd64.whl
| Download URL | url_jail-0.2.0-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 2.3 MB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
76c5eb9596ac046f9cece20bf05c0c932f40ce5b0e7d9fc33c6003f5bae4ae24
|
|
BLAKE2b-256 checksum How to use checksums |
8850c4759ea7def68f27068f0b5478363e83b02032e3d3a0f93f7e42214f37a1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl
| Download URL | url_jail-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.12 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
296717c16ae7a30b0566df99f209a8b4cc419587e2bd6240fe49733c8d41223b
|
|
BLAKE2b-256 checksum How to use checksums |
52e97757faa0ccfc2aba822dbb0b3c4043c474e81ee770e54ced40c9aca4f5e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | url_jail-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
b8fec776db25a8fb178628787db86ad66991862f0e4624c3f296b42e91b7ea5a
|
|
BLAKE2b-256 checksum How to use checksums |
e31fbde057519c7396c4086d11b6b6e77d2ce7b49550d0d7eb8c857eebc1f2cf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp312-cp312-macosx_11_0_arm64.whl
| Download URL | url_jail-0.2.0-cp312-cp312-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.12 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
30c8308e4c9013c09f3acd7fca1e2f8931371cad68090e73f2574f92ef472c4d
|
|
BLAKE2b-256 checksum How to use checksums |
ce776a97c4db295522e6bdee4952bdbbd2c70f194c45a0bf8f0f7e7e1f1e43f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp311-cp311-win_amd64.whl
| Download URL | url_jail-0.2.0-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 2.3 MB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
8f219cc899f911afc36df8e5fccf786fcf489eb192ea52de753f04dde12e93bd
|
|
BLAKE2b-256 checksum How to use checksums |
086a870c11fb4f3c583e942cecee29986ded62ec306a072308d9709795d35a56
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl
| Download URL | url_jail-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.11 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
89e7282c553b0de4a42ef90b325fea1235d0a8781e00cdfc24f7f8fff40e97c8
|
|
BLAKE2b-256 checksum How to use checksums |
3a0303172edc59794a6253f61cbba1ae5590caddefef9c8856e3e1cc394314ed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | url_jail-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
85e4d6b57dee67bcc801369dfc01a5b33bdc94e86d5e07e039949c0f8f04634b
|
|
BLAKE2b-256 checksum How to use checksums |
17acb84aa1b5b45a8e83429b611be85cd5bf034d6a5592387793a010ea53d5f1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp311-cp311-macosx_11_0_arm64.whl
| Download URL | url_jail-0.2.0-cp311-cp311-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.11 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
696dc79bc83e509986e86a64235a88ae2b14d32174b8f01c6078d1a745eb4227
|
|
BLAKE2b-256 checksum How to use checksums |
fabc59c50261754de4c963d378c2503f8497b54b7c4527a8748e3dd06e01425b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp310-cp310-win_amd64.whl
| Download URL | url_jail-0.2.0-cp310-cp310-win_amd64.whl |
|---|---|
| Size | 2.3 MB |
| Tags | CPython 3.10 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
1b69196b618fe89b763a32b32730cd74ad1eaa7fcd1cccb8a7957ce2d8edc956
|
|
BLAKE2b-256 checksum How to use checksums |
3bb8dc967e1743143f8d0f6510260392d42aebe15a38e7fc3ad9354e98fd5d96
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl
| Download URL | url_jail-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
124f4560cf3aa0f510d2f764ad9caf67d08d99fe88d9ade4ec49d62db3f785e5
|
|
BLAKE2b-256 checksum How to use checksums |
1af3e576ceaefac69fa9eb7228996fbdf8163964b648c7ecfbcad31da5f7f64f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | url_jail-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
ac7e4778cc86489665037ec357ec689d7d7693ebbe735b2ac5eeaff84d546c9e
|
|
BLAKE2b-256 checksum How to use checksums |
7c5512d3ac8363fa9a65bf4981138371dbef19a5aff903bcb1b4748e6f04685a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp310-cp310-macosx_11_0_arm64.whl
| Download URL | url_jail-0.2.0-cp310-cp310-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.10 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
b6118aee9d8c0b588a3420cb5519a4ed7c20d46b6c10f6a64df70242174c26f6
|
|
BLAKE2b-256 checksum How to use checksums |
961e69530a05411e30b3af32557b0c331270264000f181f3bcc7cc588467dd38
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp39-cp39-win_amd64.whl
| Download URL | url_jail-0.2.0-cp39-cp39-win_amd64.whl |
|---|---|
| Size | 2.3 MB |
| Tags | CPython 3.9 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
06655756c17633c56ec9be7d45460a0d1fc377bc57acfe28d081880e35b7ddb7
|
|
BLAKE2b-256 checksum How to use checksums |
6a9c67f4913a530f93be9bb4a503433295013ff1d0977e63ad5d8bd4a500e97e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl
| Download URL | url_jail-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.9 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
f995088faf333bbf5c7813c47d80ba4f5b5214935bf07f42ec00e6f88d6abc3d
|
|
BLAKE2b-256 checksum How to use checksums |
d1203978fe373de1892df860637e5b4e7548b08e78e8be31457eeef0edc59213
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | url_jail-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | CPython 3.9 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
b77bc88aff055c5cad5ebb23811c735ab3283feadc36aa030635d179e0cc43e1
|
|
BLAKE2b-256 checksum How to use checksums |
beb1602df8707e6091a325fa03ed7ea4f08a245fb5a2b7a6b9a2bb26380b734b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / url_jail-0.2.0-cp39-cp39-macosx_11_0_arm64.whl
| Download URL | url_jail-0.2.0-cp39-cp39-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.9 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
86e92c6a6f3d57666bfe47fd7f50134e8e75a67dd724397e216f60a9f9dd0142
|
|
BLAKE2b-256 checksum How to use checksums |
30f8ba32ff5f11c89d012b83bcbe828b022ab4a54aa4ccc018bdfa6de4f18fe3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|