Skip to content
Deep Dive

AI Agent Policy URL Security

Remote policy fetch is privileged egress. Treat it like one.

Deep Dive10 min readApr 2026
TL;DR
  • -If policy is loaded from a URL, SSRF becomes a governance integrity risk, not only a web-app bug.
  • -Cordum applies URL host checks before request and again at dial time, which helps against DNS rebinding.
  • -Allowlist entries are suffix-matched (`example.com` also matches `sub.example.com`), so trust boundaries must be explicit.
  • -Production blocks initial HTTP URLs; add a redirect-scheme guard and keep signature verification enabled.
Egress guard

Host allowlist and private-address blocking are enforced before outbound policy fetch.

Redirect control

Each redirect URL is revalidated and the chain is capped at five hops.

Policy integrity

Keep signature verification on, so even a reachable URL cannot inject unsigned policy.

Scope

This guide covers policy URL fetch hardening for the Safety Kernel loader path. It focuses on pre-dispatch governance impact, not generic API proxy SSRF patterns.

The production problem

A remote policy URL can change agent behavior without shipping new code. That is convenient for rollouts and dangerous for the same reason.

If attackers influence that fetch path, they can try redirects, DNS rebinding, metadata endpoint access, or oversized payloads. One weak boundary turns your governance layer into a network client under attacker direction.

The hard part is not listing SSRF payloads. The hard part is building fetch rules that survive real bypass techniques while keeping operations practical.

What top results miss

SourceStrong coverageMissing piece
OWASP SSRF Prevention Cheat SheetAllowlist guidance, parser pitfalls, DNS/IP validation, and network-layer controls.No control-plane mapping for policy loaders where fetched bytes directly change runtime decisions.
PortSwigger URL Validation Bypass Cheat SheetPractical bypass payloads for host validation, parser confusion, and redirect abuse.No production operator guidance for safe policy fetch rollouts in autonomous agent control planes.
AWS Security Blog: IMDSv2 migrationCloud metadata abuse risk and hardening controls that reduce credential theft impact.No mapping to policy-engine fetch pipelines where policy bytes directly change decision logic.

The gap is control-plane specificity: how these protections map to policy reload, signature requirements, and fail-open/fail-closed governance semantics.

They also miss trust-surface details that matter in real systems: suffix allowlists, redirect downgrade edges, and who owns each permitted subdomain.

Attack path model

StepAttacker moveRequired defense
Attacker-controlled URL valueSupply external endpoint or crafted hostname to influence policy sourceLoad policy only from explicit allowlisted hostnames
DNS rebindingSafe hostname resolves to private IP after initial validationResolve host during validation and again before dial
Redirect pivotAllowed URL redirects to internal service or metadata endpointRevalidate every redirect target and cap chain length
Oversized payloadLarge response attempts resource exhaustionEnforce hard byte limits and reject bodies above limit
Unsigned policy injectionServe reachable but malicious policy fileRequire signature verification before parse and snapshot update

Most incident writeups stop at metadata theft. For AI control planes, the blast radius can include policy mutation itself. Treat the policy URL as a high-trust artifact path.

Cordum runtime behavior

BoundaryCurrent behaviorOperational impact
Scheme handlingRemote fetch is only entered for `http://` or `https://` policy sources.Non-HTTP schemes do not enter this fetch path.
Production TLS rule`http://` policy URLs are rejected in production.Reduces MITM and downgrade risk on policy transport.
Host policy`SAFETY_POLICY_URL_ALLOWLIST` supports comma-separated host constraints.Limits fetches to approved domains and blocks unknown hosts.
Allowlist match semanticsHost checks allow exact match and subdomain suffix match (`host == entry || hasSuffix('.'+entry)`).`example.com` also trusts `a.example.com`; review subdomain ownership and takeover risk.
Private network blockPrivate/loopback/link-local hosts are denied unless `SAFETY_POLICY_URL_ALLOW_PRIVATE=true`.Blocks common SSRF targets such as metadata services by default.
Rebinding resistanceDNS resolution runs in URL validation and again in `DialContext`.Reduces time-of-check vs time-of-use gaps.
Operational limitsHTTP client timeout is 10s, redirect limit is 5, size default is 2,097,152 bytes.Caps fetch latency and payload size during policy reloads.
Redirect scheme ruleIn production, initial URL must be HTTPS; redirect targets are host-validated but not explicitly HTTPS-gated.Add a redirect-scheme guard to prevent HTTPS-to-HTTP downgrade hops.

Implementation examples

Fetch guard path (Go)

policy_url_fetch_guard.go
Go
func fetchPolicyURL(raw string) ([]byte, error) {
  parsed, err := url.Parse(raw)
  if err != nil {
    return nil, fmt.Errorf("invalid policy url: %w", err)
  }
  if env.IsProduction() && parsed.Scheme == "http" {
    return nil, fmt.Errorf("HTTPS required for policy URL in production")
  }
  if err := validatePolicyURL(parsed); err != nil {
    return nil, err
  }

  transport := http.DefaultTransport.(*http.Transport).Clone()
  transport.DialContext = policyDialContext

  client := &http.Client{
    Timeout:   10 * time.Second,
    Transport: transport,
    CheckRedirect: func(req *http.Request, via []*http.Request) error {
      if len(via) >= 5 {
        return errors.New("policy fetch redirect limit exceeded")
      }
      return validatePolicyURL(req.URL)
    },
  }

  // Fetch response and enforce policyMaxBytes() before parse.
  return readPolicyBody(resp.Body, policyMaxBytes())
}

Recommended redirect-scheme guard

policy_url_redirect_guard.go
Go
CheckRedirect: func(req *http.Request, via []*http.Request) error {
  if len(via) >= 5 {
    return errors.New("policy fetch redirect limit exceeded")
  }
  if env.IsProduction() && req.URL.Scheme != "https" {
    return fmt.Errorf("HTTPS redirect target required: %s", req.URL.Host)
  }
  return validatePolicyURL(req.URL)
}

Production env baseline

policy_url_hardening.env
Bash
# Remote policy source
export SAFETY_POLICY_URL=https://policy.corp.example/prod/safety.yaml

# SSRF controls
export SAFETY_POLICY_URL_ALLOWLIST=policy.corp.example
export SAFETY_POLICY_URL_ALLOW_PRIVATE=false
export SAFETY_POLICY_MAX_BYTES=2097152

# Integrity control (recommended with remote URLs)
export SAFETY_POLICY_SIGNATURE_REQUIRED=true
export SAFETY_POLICY_PUBLIC_KEY="<base64-or-hex-ed25519-public-key>"
export SAFETY_POLICY_SIGNATURE_PATH=/etc/cordum/policy.sig

Abuse simulation drill

policy_url_ssrf_drill.sh
Bash
# 1) Confirm happy path host passes allowlist
export SAFETY_POLICY_URL=https://policy.corp.example/prod/safety.yaml

# 2) Attempt metadata endpoint (should fail)
export SAFETY_POLICY_URL=http://169.254.169.254/latest/meta-data/
# expect: "policy url host not allowed"

# 3) Attempt non-allowlisted host (should fail)
export SAFETY_POLICY_URL=https://attacker.example/policy.yaml
# expect: "policy url host not allowed"

# 4) Restore valid URL and verify signature check remains enabled
export SAFETY_POLICY_URL=https://policy.corp.example/prod/safety.yaml

Limitations and tradeoffs

  • - Strict allowlists reduce risk but add rollout friction for new policy hosts.
  • - Blocking private hosts by default can conflict with internal artifact storage designs.
  • - DNS checks lower rebinding risk, but resolver trust and DNS cache behavior still matter.
  • - Suffix allowlists simplify operations and increase blast radius if one subdomain is compromised.
  • - Initial HTTPS enforcement is not enough if redirect targets are allowed to downgrade to HTTP.
  • - A secure URL path still needs signature enforcement, or reachable tampered policy can pass through.

If you enable `SAFETY_POLICY_URL_ALLOW_PRIVATE=true` in production, document the reason and add explicit compensating controls. Future you will ask why this was allowed.

Next step

Run this hardening checklist this week:

  1. 1. Pin `SAFETY_POLICY_URL` to a dedicated host and enforce `SAFETY_POLICY_URL_ALLOWLIST`.
  2. 2. Keep `SAFETY_POLICY_URL_ALLOW_PRIVATE=false` in production unless you have a reviewed exception.
  3. 3. Add redirect-scheme enforcement so production redirects cannot downgrade to `http`.
  4. 4. Set `SAFETY_POLICY_SIGNATURE_REQUIRED=true` and verify reload behavior on bad signatures.
  5. 5. Execute one SSRF drill with redirect and metadata targets, then capture alert evidence.

Continue with Policy Signature Verification and LLM Safety Kernel.

Policy URL fetch is not a helper

It is part of your safety boundary. Give it the same rigor as authn, signing, and deployment controls.