Skip to content

Back to the catalog

Red Agentの視点:いかにして推論を重ねてSSRFへと至ったか
wiz.iowriteup

Red Agentの視点:いかにして推論を重ねてSSRFへと至ったか

Wiz walks through how its autonomous 'Red Agent' AI pentesting tool chained an SSRF vulnerability in a GCP Cloud Run service's ?url= file-fetch parameter into a full local file read, bypassing a strict GitHub-blob-URL validator. The breakthrough payload (github.com/x/y/blob/z//proc/self/environ) exploited a parser differential between the validator and the fetcher, letting the agent exfiltrate live GCP service-account credentials and the app's source code after 96 requests of iterative hypothesis-driven probing.

TL;DR Wiz's Red Agent AI pentester chained a strict GitHub-URL SSRF filter bypass (double-slash absolute path trick) into GCP credential theft via /proc/self/environ on Cloud Run.
Document

What it is

A worked SSRF-to-local-file-read against a GCP Cloud Run endpoint (<redacted>.run.app/f) with a ?url= fetch parameter, discovered by Wiz's autonomous "Red Agent." The summary gives the payload and outcome; what it can't carry is the exact validator contract and why the bypass worked — the part an engineer writing a URL allow-lister needs.

How it works

The validator only accepted URLs matching the structure https://github.com/{owner}/{repo}/blob/{branch}/{path}, and it was strict about both the scheme (https://) and the resolved hostname — not just the domain string. This is why two earlier avenues died:

  • Direct metadata pivot to http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token was rejected (wrong host).
  • URL-confusion / parser-differential tricks to make the validator see github.com while the fetcher hit the metadata host all failed — proving the fetcher makes a real outbound HTTP request to the resolved host, not a spoofable one.

The actual flaw is a prefix-vs-path split: the validator checked that the string began with a valid GitHub blob URL, while the downstream file-reader interpreted a trailing // + absolute path as a local filesystem path. So github.com/x/y/blob/z//proc/self/environ passes validation on its prefix but reads /proc/self/environ locally. The // is the anchor, not the payload — it lets /proc/self/environ or /app/graph_api.py slip past.

Path traversal alone (../../../../etc/passwd, URL/double-encoded, null-byte ..%00/, backslash, overlong-UTF8 ..%c0%af, ....//) was all blocked, confirming the validator parsed full URL structure rather than sanitizing the path component.

What to do

If you validate a URL and then hand the raw string to a separate fetcher, this is your bug class. Validate the fully parsed/canonicalized URL that the fetcher will actually use, not a prefix. Reading /proc/self/environ here leaked live, working GCP service-account credentials and full source — treat container env-var secrets as reachable through any file-read primitive.

Caveats

This is a Wiz product-marketing post for its Red Agent; the endpoint is redacted and not independently reproducible. The //-absolute-path behavior is specific to how this particular fetcher resolved paths — verify against your own fetch library rather than assuming it generalizes.

Organisations named here

  • Red Agent

Technologies named here

  • GCP Cloud Run
  • Red Agent
  • graph-explorer
  • GCP
  • Wiz

Techniques named here

  • SSRF-to-Local-File-Read
  • Cloud metadata endpoint querying
  • Path traversal
  • URL parser confusion / parser differential
  • Repo name injection
  • Real repo enumeration / fingerprinting
  • Double-slash absolute path bypass
  • Credential exfiltration via /proc/self/environ
  • Source code disclosure
  • SSRF

Threat actors named here

  • Red Agent