Advocate

A drop-in wrapper around Python's requests library that blocks SSRF attacks by validating every socket connection before it opens.

Library
PyPI
v1.0.0
96stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
28/100Needs Attention
Development Activity0
Maintenance0
Community40
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
70/100Good
Architecture78
Code Quality68
Innovation62
Learning Curve72

Advocate is a set of tools built around the requests library for safely making HTTP requests on behalf of a third party. It exists to prevent server-side request forgery (SSRF) attacks by inspecting the actual address that requests is about to connect to — not just the URL string — and rejecting connections to private, loopback, link-local, multicast, or otherwise internal-looking addresses.

Because Advocate hooks into the same getaddrinfo call that requests/urllib3 uses to open the socket, it avoids the DNS-rebinding class of bugs that plague URL-parsing-based SSRF filters: the address it validates is guaranteed to be the address it connects to. Advocate is a mostly drop-in replacement for requests — swap the import and most code keeps working — with a configurable AddrValidator for IP/hostname/port allow- and block-lists. The project is explicitly unmaintained, so it should be evaluated as a reference implementation or forked rather than used as-is in new production systems.

What You Get

  • A near drop-in replacement for requestsadvocate.get(), advocate.Session(), and the rest of the familiar API surface
  • An AddrValidator class for configuring IP/hostname/port allow- and block-lists, with sane secure defaults (blocks private, loopback, link-local, multicast, and reserved ranges)
  • Single-lookup validation that checks the same getaddrinfo result it connects with, closing the classic DNS-rebinding gap between check-time and connect-time
  • Automatic redirect inspection — every hop in a redirect chain is validated, not just the initial URL
  • A RequestsAPIWrapper helper for sharing one validator config across an app without threading a validator kwarg through every call site
  • Optional requests-futures integration via advocate.futures.FuturesSession for async-friendly code

Common Use Cases

  • Fetching a URL supplied by an untrusted user or third-party integration (webhooks, link unfurling, avatar/image fetchers, og:image scrapers)
  • Building a webhook-delivery or callback system that must not be tricked into hitting internal metadata endpoints or admin panels
  • Any server-side “fetch this URL for me” feature (PDF renderers, screenshot services, RSS readers, SSRF-prone import tools) that accepts attacker-influenced input
  • Auditing or reference implementation work: studying a well-documented, single-getaddrinfo-call approach to SSRF prevention before rolling your own

Under The Hood

Architecture Advocate layers into requests at the socket-connection level rather than the URL-parsing level: advocate.Session subclasses requests.Session, locks down mount() to prevent adapters from being swapped out, and installs a ValidatingHTTPAdapter (adapters.py) for both http:// and https://. That adapter builds a ValidatingPoolManager (poolmanager.py) whose connection classes override _new_conn to call validating_create_connection (connection.py), which performs a single getaddrinfo call, runs the resolved address through AddrValidator.is_addrinfo_allowed (addrvalidator.py), and only then opens the socket — so the address that’s checked is guaranteed to be the address that’s connected to, closing the classic DNS-rebinding TOCTOU gap. Redirects are re-validated on every hop because they flow back through the same adapter.

Tech Stack Pure Python (100%), targeting CPython 3.6+. Runtime dependencies are requests (2.18–3.0), urllib3 (1.22–2.0), and netifaces for local-interface autodetection; requests-futures is an optional soft dependency wrapped in advocate/futures.py. No build step beyond a standard setup.py/setuptools packaging; no async runtime, no compiled extensions.

Code Quality The package is small (~1,600 lines including tests) and the core validation logic in addrvalidator.py and connection.py is heavily commented, explaining the reasoning behind each blocked IP class (link-local, 6to4 relay, Teredo, DNS64, site-local) with citations to relevant RFCs and prior SSRF research. test/test_advocate.py is a substantial 699-line suite exercising the requests test suite plus Advocate-specific validator behavior, run via pytest-cov. Naming and exception hierarchy (AdvocateException subclasses) are consistent, though a few TODOs remain unresolved (e.g. hostname-blacklist pattern normalization) and IPv6 support is explicitly flagged in the README as a work in progress.

API Design The public API is deliberately shaped to mirror requestsadvocate.get/post/put/session() and advocate.Session() — so adopting it in an existing codebase is close to a one-line import swap. Configuration is centralized in a single AddrValidator object passed via a validator kwarg, and RequestsAPIWrapper lets a team bake one validator config into a reusable module-level advocate-like object instead of repeating the kwarg everywhere. The tradeoff for that low-friction API is thin documentation beyond the README — there’s no dedicated docs site, and API reference detail lives in docstrings and the README’s example blocks.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search