HIGH llm data leakageadonisjsapi keys

Llm Data Leakage in Adonisjs with Api Keys

Llm Data Leakage in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability

AdonisJS applications that expose HTTP API keys to large language model (LLM) endpoints can inadvertently leak sensitive credentials through prompts, tool usage, or generated code. When API keys are embedded in route handlers, environment files, or service classes and an LLM endpoint is reachable from the application, the risk of data leakage arises from how prompts are constructed and how LLM responses are handled.

Consider a route that forwards user input to an LLM for code suggestions while also attaching an API key for another service:

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { OpenAI } from 'openai'

export default class AiController {
  public async chatWithCompletion({ request, response }: HttpContextContract) {
    const userMessage = request.input('message')
    const apiKey = process.env.OPENAI_API_KEY // sensitive key

    const openai = new OpenAI({ apiKey })
    const chatCompletion = await openai.chat.completions.create({
      messages: [{ role: 'user', content: userMessage }],
      model: 'gpt-3.5-turbo',
    })

    return response.json(chatCompletion.choices[0]?.message?.content)
  }
}

If the developer includes the API key in the prompt (e.g., to authorize downstream calls) or logs full request/response pairs, the key can be exposed through LLM outputs, cached traces, or error messages. For example, passing the key explicitly in the prompt:

const chatCompletion = await openai.chat.completions.create({
  messages: [
    { role: 'system', content: `Use API key ${process.env.OPENAI_API_KEY} for authenticated requests.` },
    { role: 'user', content: userMessage },
  ],
  model: 'gpt-3.5-turbo',
})

This pattern risks leaking the key in LLM responses if the model echoes system instructions or if output scanning is not applied. Similarly, logging prompts for debugging can persist keys in application logs that may be accessed by unauthorized parties.

AdonisJS applications using environment-based configuration must ensure that sensitive values are never interpolated into prompts or exposed through tool schemas. The framework’s config system should treat API keys as runtime secrets, referenced via process.env, and never serialized into user-facing contexts. Without explicit guardrails, an LLM endpoint that accepts user-influenced prompts can become an inadvertent exfiltration channel for API keys, especially when combined with insufficient output validation or permissive CORS settings.

Effective mitigation combines input validation, strict prompt construction, and runtime output inspection to prevent sensitive data from appearing in LLM interactions.

Api Keys-Specific Remediation in Adonisjs — concrete code fixes

Remediation focuses on isolating API keys from prompt content, avoiding their inclusion in logs, and validating LLM outputs. Below are concrete patterns for AdonisJS that reduce the risk of LLM-driven data leakage.

1) Keep API keys out of prompts and system messages:

import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { OpenAI } from 'openai'

export default class AiController {
  public async chatCompletion({ request, response }: HttpContextContract) {
    const userMessage = request.input('message')

    const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
    const chatCompletion = await openai.chat.completions.create({
      messages: [{ role: 'user', content: userMessage }],
      model: 'gpt-3.5-turbo',
    })

    return response.json(chatCompletion.choices[0]?.message?.content)
  }
}

2) Use AdonisJS config to centralize secrets and avoid inline references:

// config/openai.ts
export default {
  apiKey: process.env.OPENAI_API_KEY,
}

// In controller
import Config from '@ioc:Adonis/Core/Config'
const apiKey = Config.get('openai.apiKey')
const openai = new OpenAI({ apiKey })

3) Validate and sanitize LLM outputs before use:

export default class AiController {
  public async safeCompletion({ request, response }: HttpContextContract) {
    const userMessage = request.input('message')
    const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
    const chatCompletion = await openai.chat.completions.create({
      messages: [{ role: 'user', content: userMessage }],
      model: 'gpt-3.5-turbo',
    })

    const raw = chatCompletion.choices[0]?.message?.content || ''
    if (this.containsSensitiveData(raw)) {
      return response.badRequest({ error: 'Invalid response from LLM' })
    }
    return response.json({ content: raw })
  }

  private containsSensitiveData(text: string): boolean {
    const apiKeyPattern = /\b[a-zA-Z0-9_\-]{30,}\b/ // naive example; use stricter checks
    return apiKeyPattern.test(text)
  }
}

4) Audit and restrict logging to avoid persisting keys:

// Avoid logging full messages or API keys
export default class ApiLogger {
  public static logRequest(path: string, userMessage: string) {
    // Log only non-sensitive metadata
    console.info({ path, timestamp: new Date().toISOString(), userMessageHash: require('crypto').createHash('sha256').update(userMessage).digest('hex') })
  }
}

5) Enforce environment-level protections and CI checks:

  • Use .env files with proper .gitignore to prevent commits of API keys.
  • Add a pre-commit hook or CI check to detect accidental key patterns in code.

These practices help ensure API keys remain server-side secrets and are not exposed through LLM interactions or application artifacts.

Related CWEs: llmSecurity

CWE IDNameSeverity
CWE-754Improper Check for Unusual or Exceptional Conditions MEDIUM

Frequently Asked Questions

How can I verify that my AdonisJS app is not leaking API keys through LLM outputs?
Run scans that include output validation and prompt inspection, and audit logs to ensure API keys are not stored or echoed. Use code patterns that keep keys out of prompts and validate LLM responses before use.
Is it safe to pass API keys as part of tool schemas or function descriptions in AdonisJS?
No. Passing API keys in tool schemas or descriptions risks exposing them in LLM interactions and logs. Keep keys in environment variables and reference them securely without embedding in prompts or tool definitions.