HIGH prototype pollutionadonisjsapi keys

Prototype Pollution in Adonisjs with Api Keys

Prototype Pollution in Adonisjs with Api Keys — how this specific combination creates or exposes the vulnerability

Prototype pollution in AdonisJS can intersect with API key handling when request payloads or configuration objects are merged into shared prototypes. If an endpoint accepts user input to update settings or extend objects used by API key validation logic, an attacker can inject properties such as __proto__, constructor.prototype, or prototype to modify behavior across the application. This becomes critical when API keys are stored or compared on shared objects, or when key-validation utilities are implemented as reusable modules attached to prototypes.

For example, consider an AdonisJS route that merges request body into a configuration object used for API key verification:

// routes.ts or controller handler
import { schema } from '@ioc:Adonis/Core/Validator'

const apiKeySchema = schema.create({
  api_key: schema.string(),
  config: schema.object({}, {
    // vulnerable: allows arbitrary keys
    allowNamespaced: schema.boolean.optional(),
  }).optional(),
})

export async function updateKeyConfig({ request, response }: HttpContextContract) {
  const payload = request.validate({ schema: apiKeySchema })
  // Dangerous: merging user input into a shared/prototype-based config
  Object.assign(SharedConfig.prototype.defaults, payload.config)
  // API key check later uses SharedConfig.prototype.defaults
  const isValid = validateApiKey(payload.api_key)
  return response.ok({ isValid })
}

If an attacker sends { "config": { "__proto__": { "isAdmin": true } } }, the merged prototype gains an isAdmin property. If validateApiKey or related authorization logic checks inherited properties (e.g., config.isAdmin), the attacker can bypass intended restrictions. This pattern is relevant when API key scopes or roles are derived from prototype-inherited defaults, effectively enabling privilege escalation without a direct IDOR on the key itself.

The 12 security checks in middleBrick run in parallel and would flag this as BOLA/IDOR and Property Authorization risk when it observes prototype-modifying operations on shared objects influenced by API key–related logic. The scanner cross-references OpenAPI/Swagger 2.0/3.0/3.1 definitions with runtime behavior, detecting dangerous merges even when the API spec describes only key submission without detailing server-side object handling.

Additionally, if an AdonisJS application exposes an unauthenticated endpoint that returns API key metadata or configuration, and that endpoint processes user-influenced input into prototype chains, middleBrick’s LLM/AI Security checks help identify whether system prompt leakage or output data exfiltration could compound the issue by exposing key-related artifacts.

Api Keys-Specific Remediation in Adonisjs — concrete code fixes

Remediation focuses on preventing prototype pollution at the point where user input merges into objects used by API key validation, and on ensuring API keys are handled as opaque, isolated values.

  • Use strict schema validation that disallows prototype pollution vectors. In AdonisJS, prefer the built-in validator with schemas that do not allow arbitrary keys.
// routes.ts — safe schema that rejects prototype keys
import { schema } from '@ioc:Adonis/Core/Validator'

const safeApiKeySchema = schema.create({
  api_key: schema.string({}, { trim: true }),
  config: schema.object({
    // explicitly list allowed fields; do not use "any"
    allowCache: schema.boolean.optional(),
    ttl: schema.number.optional(),
  }, { allowUndefined: true }), // do not allow arbitrary keys
})

export async function updateKeyConfigSafe({ request, response }: HttpContextContract) {
  const payload = await request.validate({ schema: safeApiKeySchema })
  // Apply only known fields; avoid merging into prototypes
  const config = {
    allowCache: payload.config?.allowCache ?? false,
    ttl: payload.config?.ttl ?? 3600,
  }
  // Use config as a plain object, not attached to prototypes
  await storeKeyConfig(config)
  const isValid = validateApiKey(payload.api_key)
  return response.ok({ isValid })
}
  • Avoid Object.assign or spread on shared prototypes. Instead, work with plain objects or use defensive copies.
// service.ts — safe handling
export function storeKeyConfig(input: Record<string, unknown>) {
  // Defensive copy; do not merge into any prototype chain
  const config = { ...input } // only copies own enumerable properties
  // Persist config without linking to Object.prototype extensions
  writeConfigToVault(config)
}
  • Treat API keys as secrets; do not embed them in objects that become part of prototypes. Validate and compare keys using constant-time checks where feasible, and ensure key-related configuration is scoped to request context or isolated singletons.
// auth.ts — constant-time comparison stub
import { timingSafeEqual } from 'node:crypto'

export function validateApiKey(candidate: string): boolean {
  const expected = getStoredKeyHash() // Buffer
  const candidateBuf = Buffer.from(candidate)
  // Ensure buffers are same length to prevent timing leaks
  if (candidateBuf.length !== expected.length) return false
  return timingSafeEqual(candidateBuf, expected)
}

middleBrick’s CLI (middlebrick scan <url>) can be integrated into scripts to verify that endpoints accepting API key configuration do not exhibit prototype pollution patterns. The Pro plan’s continuous monitoring can alert when new endpoints introduce risky merges, and the GitHub Action can fail builds if such patterns are detected in OpenAPI specs or runtime behavior.

Frequently Asked Questions

Can prototype pollution in AdonisJS allow attackers to tamper with API key validation?
Yes, if user-controlled input is merged into shared objects or prototypes used by API key validation logic, attackers can inject properties that alter behavior, potentially bypassing key checks or escalating privileges.
What is the most effective mitigation for API key–related prototype pollution in AdonisJS?
Use strict, field-specific schemas that reject arbitrary keys, avoid merging user input into prototypes or shared configuration objects, and treat API keys as opaque values compared with constant-time checks.