GHSA-2v2f-mvfg-ph56 meta-ads-mcp: X-Pipeboard-Token Header Auth Bypass Reuses Operator Meta Token
X-Pipeboard-Token Header Auth Bypass Reuses Operator Meta TokenSummary`AuthInjectionMiddleware` in `meta-ads-mcp` rejects HTTP MCP requests only when **both** `auth_token` and `pipeboard_token` are absent. Because `extract_token_from_headers()` does not recognise the `X-Pipeboard-Token` header, an attacker who sends that header with any arbitrary value produces `auth_token = None` and `pipeboard_token = <attacker value>`, making the guard condition evaluate to `False` and passing the request through. No authentication context is set; the token getter falls back to the server operator's `META_ACCESS_TOKEN` environment variable. Every subsequent MCP tool call executes with the operator's Meta credentials, allowing an unauthenticated network caller to read and write the operator's Meta Ads data.DetailsThe vulnerable condition is at `meta_ads_mcp/core/http_auth_integration.py:259`:`extract_token_from_headers()` (lines 77–95) recognises only `Authorization: Bearer`, `X-META-ACCESS-TOKEN`, and `X-PIPEBOARD-API-TOKEN`. It does **not** recognise `X-Pipeboard-Token`, so that header never populates `auth_token`.`extract_pipeboard_token_from_headers()` (line 108) **does** recognise `X-Pipeboard-Token`, so sending that header alone produces:After the bypass, `set_auth_token()` is never called (lines 283–291 only run when `auth_token` is truthy). The patched token getter at lines 163–168 resolves `get_auth_token() = None`, then delegates to `original_get_current_access_token()`. The fallback chain in `auth.py:446–453` returns `META_ACCESS_TOKEN` from the server environment:`@meta_api_tool` at `api.py:390–396` injects this operator token into every tool's `access_token` kwarg. The sink at `api.py:225–235` forwards it to the Meta Graph API via `httpx.AsyncClient`. Verified with `accounts.py:42–62` (`get_ad_accounts`): the operator's ad account data is returned for valid tokens; for invalid tokens the Meta Graph API responds with an `OAuthException`, confirming the token traversed the full path.Full data flow:| Step | Location | Description |
|------|----------|-------------|
| 1 | `http_auth_integration.py:255–257` | Middleware extracts attacker-controlled headers |
| 2 | `http_auth_integration.py:259` | Bypass: `X-Pipeboard-Token` alone satisfies guard |
| 3 | `http_auth_integration.py:288–291` | `auth_token` is `None`; auth context never set |
| 4 | `http_auth_integration.py:163–168` | Token getter falls back to original accessor |
| 5 | `auth.py:446–453` | `META_ACCESS_TOKEN` env var returned as access token |
| 6 | `api.py:390–396` | Operator token injected into tool kwargs |
| 7 | `accounts.py:42–62` | Tool invokes Meta Graph API with operator token |
| 8 | `api.py:225–235` | `httpx.AsyncClient` sends privileged HTTP request |**Recommended fix:**`X-Pipeboard-Token` should be treated as a supplementary service token only; it must not serve as a standalone authentication credential for MCP tool calls.PoC**Prerequisites**Docker installed and the `meta-ads-mcp` repository available locally.The server must be started in `streamable-http` mode (documented in `STREAMABLE_HTTP_SETUP.md` as a supported production deployment).**Step 1 — Build the Docker image**The `Dockerfile` installs the package from source, sets `META_ACCESS_TOKEN=FAKE_OPERATOR_META_TOKEN_ABCDEF1234567890`, and starts the server on port 8080.**Step 2 — Run the container****Step 3 — Confirm the middleware is active (no-auth → 401)****Step 4 — Trigger the bypass (X-Pipeboard-Token only → 200)****Step 5 — Confirm operator token is forwarded to Meta Graph API****Automated PoC script**The script performs Tests 1–3 and prints `RESULT: PASS — VULN-001 reproduced` on success.**Observed output (dynamic reproduction)**Test 3 confirms that `FAKE_OPERATOR_META_TOKEN` was sent to Meta Graph API, proving the full operator-token reuse path.ImpactThis is an **authentication bypass** vulnerability. Any network-reachable caller that can send an HTTP request with an arbitrary `X-Pipeboard-Token` header can:**Read** all Meta Ads data accessible to the server operator (ad accounts, campaigns, creatives, audiences, insights).**Write** Meta Ads resources (create/update campaigns, ads, budgets) as the operator.**Exfiltrate the operator's identity** via Meta Graph API error responses that reference the token.Operators who deploy `meta-ads-mcp` in `--transport streamable-http` mode with `META_ACCESS_TOKEN` configured — the documented and recommended production setup — are directly affected. Deployments using the default `stdio` transport or those without `META_ACCESS_TOKEN` set are not affected.Reproduction artifacts`Dockerfile``poc.py`
CVSS v3.1 score: 7.4