Metadata-Version: 2.5
Name: url-guard
Version: 0.1.0
Summary: SSRF guard for outbound URLs: canonical IP-literal parsing in every encoding, private/metadata/link-local classification, DNS-resolved validation, HTTPS and host allow-list rules. Zero dependencies. Wire-identical to the url-guard npm package.
Project-URL: Homepage, https://github.com/mpointer/url-guard
Project-URL: Issues, https://github.com/mpointer/url-guard/issues
Author-email: Michael Pointer <mpointer@gmail.com>
License-Expression: MIT
Keywords: allowlist,egress,httpx,metadata,private-ip,requests,security,ssrf,url
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# url-guard (Python)

SSRF guard for outbound URLs. This is the Python twin of the
[@mpointer/url-guard npm package](https://www.npmjs.com/package/@mpointer/url-guard): identical
IP-literal grammar, identical classification tables, identical URL rules,
shared vectors decoded by both suites in CI. Zero dependencies.

```
pip install url-guard
```

```python
from url_guard import assert_public_url, assert_public_url_resolved, UnsafeUrlError

url = assert_public_url("https://api.example.com/v1")            # structural check, no DNS
url = assert_public_url_resolved("https://partner.example/feed")  # every resolved address must be public

assert_public_url(
    "http://docling.railway.internal:5001",
    allow_private=True,                              # self-hosted targets on the private network
    allowed_host_suffixes=(".railway.internal",),    # and nothing else
)
assert_public_url(base_url, require_https=True)      # plaintext only to loopback
```

`UnsafeUrlError` subclasses `ValueError` and carries `.reason` (`parse`,
`protocol`, `blocked-host`, `private-address`, `allow-list`, `dns`,
`timeout`), so a call site that already catches `ValueError` around its own
URL check keeps working when it switches.

See the [repository README](https://github.com/mpointer/url-guard) for the
full design: why hostname string matching is not a guard, the encodings
that are canonicalized, what `allow_private` never relaxes, the DNS rules,
and the rebinding window this does not close.
