agentsec · Tools · fetchfence

Offline · stdlib-only · MIT

fetchfence: detect SSRF and destination risk in fetched URLs in AI agents


Offline SSRF / destination-risk auditor for URLs an AI agent actually requested.

What it detects

Offline SSRF / destination-risk auditor for URLs an AI agent actually requested.

When an agent can WebFetch, browse, http_get or otherwise retrieve a URL, a prompt injection or confused tool choice can steer it at cloud-metadata endpoints, private networks, callback/OOB hosts, credentialed URLs or file:// paths. fetchfence extracts those destinations from saved transcripts (or a plain URL list), classifies each scheme/host/port/query, and reports findings with tool and turn attribution.

Standard library only. It never runs an agent and never contacts the network.

Rules

RuleSeverityWhat it flags
FF01criticalCloud metadata / link-local destinations (169.254.169.254, metadata.google.internal, …)
FF02highLoopback / localhost / ::1
FF03highPrivate RFC1918, ULA or other non-public IPs
FF04criticalDangerous schemes (file, gopher, dict, ftp, jar, data, …)
FF05highCredentials in URL userinfo (https://user:pass@…)
FF06highKnown OOB / callback hosts (webhook.site, interact.sh, ngrok, …)
FF07mediumCleartext http:// fetches
FF08mediumRaw IP-literal hosts (bypass name-based allowlists); well-known public resolvers such as 1.1.1.1 / 8.8.8.8 are skipped
FF09mediumPunycode / IDN hosts (xn--…)
FF10lowURL shortener hosts (bit.ly, t.co, …)
FF11mediumSecret-looking query parameters (api_key=, token=, …)
FF12mediumAdmin / data-store ports (6379, 9200, 27017, 2375, …) on non-public hosts
FF13highInternal / corporate hostname suffixes (.internal, .corp, .lan, .cluster.local, …)
FF14highKnown public chat/webhook API used as an unauthenticated exfil drop (Telegram Bot API /bot, Discord webhooks, Slack hooks.slack.com)

Usage

python3 fetchfence.py transcript.json [more.jsonl dir/ urls.txt -]
  --as-urls           treat inputs as plain URL lists
  --allow-host GLOB   allowlist host (repeatable); still flags userinfo + dangerous schemes
  --disable RULE ...  skip rule ids (e.g. FF07 FF10)
  --json              machine-readable output
  --min-severity S    hide findings below S (default info)
  --fail-on S         exit 1 if any finding >= S (default high; any, none)
  --list-rules

After pip install of the kit, the same options work as agentsec fetchfence …. Every tool also accepts --help and almost every tool accepts --json.

Example output

Flags FF01/FF07/FF08 on the metadata IP, FF06 on webhook.site, FF03/FF05/FF08/FF12 on the private Redis URL, and FF11 on the api_key query (exit 1). examples/clean_openai.json is clean (exit 0). See also risky_anthropic.json, generic_fetches.jsonl and urls.txt. All secrets and callback IDs in examples are FAKE-EXAMPLE-*.

python3 fetchfence.py examples/risky_openai.json

SARIF and CI

agentsec fetchfence path/to/input --sarif > fetchfence.sarif

# GitHub Actions (composite action ships with the repo)
- uses: dunkleschitz/agentsec@v0
  with:
    tools: fetchfence
    paths: path/to/input
    fail-on: high

SARIF 2.1.0 can be uploaded to GitHub code scanning. The composite action writes per-tool reports under agentsec-sarif/ by default.

OWASP mapping

Heuristic mapping of what this tool helps a reviewer look for. Not an official OWASP endorsement, and not complete coverage of any item. Sources: OWASP Top 10 for LLM Applications 2025 and OWASP Top 10 for Agentic Applications 2026.

Known limits

takes target may be missed unless the value looks like a URL; rename detection via --as-urls on an extracted list if needed.

private IP is invisible offline — fetchfence only sees the written URL.

phrasing or a deny list you enforce elsewhere.

or toolgate policy in front of the agent.

Full source, tests, and fixtures: tools/fetchfence/ in the repository. Install the kit with pip install git+https://github.com/dunkleschitz/agentsec.git.