# utcp-http SSRF: HTTP tool invocation follows redirects without re-validating the target

utcp-http validated only the pre-redirect tool URL, so an attacker-controlled endpoint could 302 the client into cloud metadata and return IAM credentials to the caller.

- Payout: Research
- Severity: high
- Program: utcp-http
- Found by: lexdotdev
- Disclosed: 2026-08-25
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-9qhg-99ww-9mqc
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-9qhg-99ww-9mqc
- Tags: area:ai domain:ai domain:web impact:data-leak impact:internal-access kind:research platform:ghsa sev:high tech:python technique:incomplete-fix technique:source-review vuln:ssrf

**Target:** UTCP HTTP communication protocol client (call_tool / register_manual)
**Root cause:** call_tool runs ensure_secure_url once on the resolved tool URL, then issues the request with aiohttp's default allow_redirects=True and never revalidates the Location target, so the redirect hop bypasses the validator entirely.
**Steps:**
1. Register a tool whose URL passes ensure_secure_url (any https:// or attacker-owned benign host) pointing at an attacker server.
2. Attacker server responds to the tool request with `302` and `Location: http://<internal-host>/latest/meta-data/iam/security-credentials/app-role`.
3. Invoke the tool via `HttpCommunicationProtocol.call_tool(None, "lookup", {}, ct)`; aiohttp auto-follows the redirect without revalidation.
4. Internal service returns the metadata JSON, which is handed back as the tool result to the caller.
**How found:** Noticed the prior SSRF fix (GHSA-39j6-4867-gg4w) added an invocation-time URL check but left the redirect hop unguarded; reading the code showed validation at line 281 before a request made with aiohttp's default allow_redirects=True at lines 313-332, so a 302 from an allowed URL reaches the blocked internal target.
**Exploitation:** Attacker influences the registered tool/manual endpoint URL (e.g. a manual or OpenAPI spec discovered from a runtime-supplied URL), returns a 3xx with Location pointing at an internal service, and the UTCP client fetches it and returns the body to the caller. On IMDSv1 cloud instances this yields the instance role's IAM credentials; otherwise internal admin panels, unauth datastores and link-local endpoints.
**Escalation:** Chains the redirect bypass with cloud IMDSv1 to obtain IAM credentials, escalating SSRF to infrastructure takeover; the same helper gap also affected the OAuth2 token-fetch path.
**Insight:** When a fix adds a URL validator, check whether the HTTP client still auto-follows redirects — the validator only sees hop one. Grep for allow_redirects defaults and re-test the exact internal targets the validator was written to block via a 302 from an allowed host.

