HIGH header injectionadonisjsfirestore

Header Injection in Adonisjs with Firestore

Header Injection in Adonisjs with Firestore — how this specific combination creates or exposes the vulnerability

Header Injection occurs when untrusted input is reflected into HTTP response headers without validation or encoding. In an AdonisJS application that integrates with Google Cloud Firestore, this typically arises when request parameters, headers, or Firestore document fields are used to construct response headers, redirect locations, or values passed to APIs that later set headers. Because AdonisJS is a Node.js framework, response headers are often set via response.header() or similar helpers, and if these values originate from Firestore documents or unvalidated query parameters, an attacker can inject malicious headers such as Set-Cookie, Location, or X-Content-Type-Options.

Firestore itself does not introduce header injection, but the way data is read and used in AdonisJS routes and controllers can create the conditions for injection. For example, a developer might retrieve a document field from Firestore that contains user-controlled data and directly assign it to a response header. Consider a route that reads a custom metadata field from a Firestore document and uses it to set a X-Custom-Reason header. If the field contains newline characters or header-like sequences (e.g., X-Injected: 1), an attacker can split the header and inject additional headers.

The risk is compounded when Firestore documents are used to store configuration or template values that influence HTTP behavior. If an attacker can modify a Firestore document (for example, via compromised credentials or a misconfigured rule), they may be able to change header values that the AdonisJS application uses. Even without direct write access, indirect paths—such as user-supplied identifiers used to look up Firestore documents—can lead to injection if the retrieved data is not strictly validated and sanitized before use in headers.

In a black-box scan, middleBrick tests for header injection by submitting inputs that include newline and carriage return sequences (e.g., %0d%0aX-Injected: injected) in parameters and headers, then inspecting the response for reflected injection. For AdonisJS apps using Firestore, ensuring strict schema validation, avoiding direct use of document fields in headers, and normalizing output are essential to mitigate this class of vulnerability.

Firestore-Specific Remediation in Adonisjs — concrete code fixes

To remediate header injection when using Firestore in AdonisJS, always treat data from Firestore as untrusted when it flows into HTTP headers. Validate and sanitize all values before using them in response.header(), redirects, or any header-like context. Below are concrete code examples showing insecure patterns and their secure alternatives.

Insecure pattern: using raw Firestore document data in headers

import { DateTime } from 'luxon'
import { Firestore } from '@google-cloud/firestore'

const firestore = new Firestore()

Route.get('/report/:id', async ({ params, response }) => {
  const doc = await firestore.doc(`reports/${params.id}`).get()
  const data = doc.data()

  // Risky: directly using Firestore field in header
  if (data && data.customHeader) {
    response.header('X-Custom-Header', data.customHeader)
  }

  response.send('ok')
})

This pattern is vulnerable if data.customHeader contains newline characters or malicious header lines. An attacker who can influence the Firestore document can inject headers.

Secure pattern: strict allow-list and sanitization

import { sanitizeHeaderValue } from '../Validators/HeaderSanitizer'

Route.get('/report/:id', async ({ params, response }) => {
  const doc = await firestore.doc(`reports/${params.id}`).get()
  const data = doc.data()

  // Safe: use allow-list and sanitize
  const safeValue = data && data.customHeader ? sanitizeHeaderValue(data.customHeader) : null
  if (safeValue) {
    response.header('X-Custom-Header', safeValue)
  }

  response.send('ok')
})

// Validators/HeaderSanitizer.js
function sanitizeHeaderValue(value) {
  if (typeof value !== 'string') return null
  // Reject newlines and control characters
  if (/[\r\n]/.test(value)) return null
  // Optionally enforce length and allowed characters
  return value.substring(0, 256).replace(/[^a-zA-Z0-9\-._~ '"\/?:@&=+$,;%]+/g, '')
}
module.exports = { sanitizeHeaderValue }

The sanitizer rejects values containing carriage returns or line feeds, which are the primary enablers of header injection. It also limits length and strips unexpected characters.

Secure pattern: using constants for security headers

Route.get('/secure-page', async ({ response }) => {
  // Set security headers from constants, not Firestore
  response.header('X-Content-Type-Options', 'nosniff')
  response.header('X-Frame-Options', 'DENY')
  response.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')

  // If you must use Firestore data, ensure it is validated
  const doc = await firestore.doc('config/security').get()
  const customCsp = doc.data()?.csp
  if (customCsp && /^[a-zA-Z0-9; '"-]+$/.test(customCsp)) {
    response.header('Content-Security-Policy', customCsp)
  }

  response.send('secure')
})

For security-critical headers, prefer hard-coded values or configuration validated at build/deploy time rather than runtime Firestore values. If Firestore is used, enforce strict regex allow-lists and avoid passing raw user-controlled strings into headers.

Additionally, review Firestore security rules to limit who can modify documents that influence headers, and ensure that route parameters used to look up documents are validated (e.g., using Route pattern constraints). middleBrick scans can help detect header injection by testing inputs that traverse Firestore lookups and response construction.

Frequently Asked Questions

What are common signs that header injection is occurring in an AdonisJS app using Firestore?
Common signs include unexpected new headers in responses (e.g., an extra Set-Cookie or X-Injected header), response splitting visible in the raw HTTP output, and 400 or 500 errors when newline characters appear in Firestore fields used for headers. middleBrick findings often highlight reflected newline sequences in headers as an indicator.
Does Firestore validation on the server fully prevent header injection in AdonisJS?
Firestore security rules control document reads and writes but do not sanitize data for HTTP header context. Even with strict Firestore rules, you must validate and sanitize any document field before using it in an HTTP header in AdonisJS. Treat Firestore data as untrusted input.