HIGH timing attackadonisjsfirestore

Timing Attack in Adonisjs with Firestore

Timing Attack in Adonisjs with Firestore — how this specific combination creates or exposes the vulnerability

A timing attack in the combination of AdonisJS and Google Cloud Firestore arises when response time differences leak information about the existence or validity of data. AdonisJS, as a Node.js framework, typically handles asynchronous operations, and Firestore client calls return promises. If the application uses branching logic based on whether a document exists, or on the outcome of a lookup, the time taken for the Firestore round trip can vary in a way that an attacker can measure.

Consider an authentication flow where an attacker supplies a username or email. The server might first query Firestore to check if the user exists, then, only if the user exists, proceed to verify the password. The time between the request and the response can be measurably longer when the user exists because of the extra steps (document retrieval and password hashing) compared to when the user does not exist (where the server may return early). This difference is observable even in unauthenticated scenarios because Firestore is an external service subject to network latency and query execution time variations.

In AdonisJS, a typical vulnerable route might look like a login endpoint that performs a Firestore get() on a users collection and conditionally continues. The variability comes from Firestore indexing and document size, as well as the cost of hashing a password with a library like bcrypt. An attacker can use high-resolution timing measurements across many requests to infer valid user identifiers. This becomes a user enumeration vector, and in some configurations, it can aid horizontal privilege escalation if role or permission flags are indirectly revealed by timing differences in subsequent Firestore reads.

Firestore-specific factors that amplify the risk include the use of collection group queries or queries with inequality filters, which may introduce additional variability depending on index state and data distribution. Also, Firestore’s eventual consistency for certain operations can cause timing differences between strong and eventual reads, though the primary concern in this context is the observable latency difference between a document miss and a document hit that triggers further processing.

To detect this during a scan, middleBrick runs checks focused on Unauthenticated LLM Security and Input Validation, but for this implementation risk, the relevant check is BOLA/IDOR combined with timing-sensitive behavior. The scanner observes whether endpoints exhibit timing-dependent branching by comparing response durations across controlled inputs, without requiring authentication.

Because Firestore is a managed service, the exact timing characteristics can vary with backend load and network conditions, but the relative differences between code paths remain exploitable. Therefore, any AdonisJS application interacting with Firestore must ensure that all data-access paths take constant time regardless of whether a record exists, preventing attackers from inferring information through careful timing measurements.

Firestore-Specific Remediation in Adonisjs — concrete code fixes

Remediation centers on making data access patterns constant-time and removing early-exit branches that depend on document existence. In AdonisJS, this means designing your service layer so that the flow for a valid user and an invalid user takes approximately the same time, even if the actual operations differ internally.

Instead of querying Firestore and branching on whether the document exists, perform a read that always proceeds to a verification step. For password checking, use a constant-time comparison approach or a deliberately slow hash that masks the timing difference, but ensure the hash computation path is always executed.

Example of a vulnerable pattern:

// Vulnerable: early return on missing document
const userDoc = await firestore.collection('users').where('email', '==', email).limit(1).get();
if (userDoc.empty) {
  return res.unauthorized();
}
const userData = userDoc.docs[0].data();
const match = await bcrypt.compare(password, userData.passwordHash);
if (!match) {
  return res.unauthorized();
}

An improved constant-time approach in AdonisJS:

// Safer: always run hashing and avoid early exits based on Firestore emptiness
const userDoc = await firestore.collection('users').where('email', '==', email).limit(1).get();
let storedHash = null;
if (!userDoc.empty) {
  storedHash = userDoc.docs[0].data().passwordHash;
}
// Use a dummy hash if no user exists to keep timing similar
const dummyHash = await bcrypt.hash(password, 10);
const actualHash = storedHash || dummyHash;
const match = await bcrypt.compare(password, actualHash);
// Perform a dummy compare with a constant dummy value to further obscure timing
await bcrypt.compare(password, await bcrypt.hash('dummy_salt_rounds_10', 10));
if (!match) {
  return res.unauthorized();
}

Additional Firestore-specific measures:

  • Use parameterized queries consistently to avoid variability introduced by query parsing or index usage differences.
  • If you must return different errors to users, ensure the timing of error path execution is masked by performing equivalent dummy operations.
  • Avoid collection group queries or inequality filters in authentication paths; prefer direct document reads by ID when possible, as they have more predictable latency characteristics.
  • Consider retrieving a small, fixed-size document even for negative cases (e.g., a placeholder document) to normalize read times, though this must be balanced against data design constraints.

These changes reduce the signal available to an attacker measuring response times, aligning the implementation with best practices for secure authentication in a serverless, managed database context.

Frequently Asked Questions

Can a timing attack infer valid Firestore document IDs even without knowing the data structure?
Yes, by measuring subtle differences in response duration across crafted queries, an attacker can sometimes infer the existence of documents or index behavior, especially when combined with knowledge of query patterns used in the application.
Does using Firestore's built-in security rules mitigate timing attacks?
No. Security rules govern authorization and validation but do not affect the network latency or server-side processing time differences that enable timing attacks. Constant-time code patterns are still required.