HIGH broken authenticationkoafirestore

Broken Authentication in Koa with Firestore

Broken Authentication in Koa with Firestore — how this specific combination creates or exposes the vulnerability

Broken Authentication occurs when identity management functions are implemented incorrectly, allowing attackers to compromise passwords, session tokens, or other credentials. In a Koa application using Google Firestore as the user store, the risk emerges from mismatches between application logic and Firestore security rules, as well as insecure session handling patterns common in JavaScript runtimes.

Koa is a minimalist web framework that does not include authentication primitives by default. Developers often introduce session-based or token-based flows by combining Koa middleware with Firestore documents that store user credentials or session records. If password hashing is omitted, sessions are not invalidated securely, or rules allow unauthenticated reads of user collections, the attack surface expands.

For example, storing passwords in Firestore without strong adaptive hashing (such as bcrypt) makes offline cracking feasible if Firestore rules are misconfigured or leaked. A rule like allow read, write: if request.auth != null; may appear protective, but if the application exposes a public endpoint that enumerates users via an unauthenticated route, attackers can harvest valid usernames or emails to aid credential stuffing or social engineering.

Another pattern specific to Koa is the use of ctx.session via koa-session or similar middleware. If session identifiers are predictable, stored client-side without integrity protection, or not bound to IP/user-agent context, an attacker who obtains a session ID can hijack authenticated sessions. Firestore-backed sessions must ensure that session documents are not readable or writable by other users and that session expiration is enforced both server-side and in Firestore TTL policies.

Additionally, over-permissive Firestore rules that allow writes to user documents from unauthenticated contexts can enable attackers to modify authentication-linked fields, such as email or password reset tokens. In Koa, route handlers that trust client-supplied identifiers (e.g., userId in path parameters) without verifying ownership can lead to Broken Object Level Authorization (BOLA), which is closely related to Broken Authentication because it enables horizontal privilege escalation across user accounts.

Real-world attack patterns include credential enumeration via timing differences in Koa route responses, brute-force attacks on weak passwords stored in Firestore, and token replay when session invalidation is incomplete. These issues are compounded when Firestore security rules are not aligned with the principle of least privilege, allowing broader access than intended. Proper authentication in the Koa–Firestore stack requires strong password hashing, tightly scoped rules, secure session storage, and explicit ownership checks on every data access.

Firestore-Specific Remediation in Koa — concrete code fixes

To remediate Broken Authentication in Koa with Firestore, adopt defense-in-depth measures: enforce strong password hashing, apply least-privilege Firestore rules, validate ownership on every request, and manage sessions securely. The following examples illustrate concrete implementations aligned with these practices.

First, use bcrypt to hash passwords before writing them to Firestore. Never store plaintext or weakly hashed credentials.

const koa = require('koa');
const router = require('koa-router')();
const bcrypt = require('bcrypt');
const { initializeApp } = require('firebase-admin');
const { getFirestore } = require('firebase-admin/firestore');

initializeApp();
const db = getFirestore();

router.post('/register', async (ctx) => {
  const { email, password } = ctx.request.body;
  const hashedPassword = await bcrypt.hash(password, 10);
  const userRef = db.collection('users').doc(email);
  await userRef.set({
    email,
    passwordHash: hashedPassword,
    createdAt: new Date(),
  });
  ctx.status = 201;
  ctx.body = { message: 'User created' };
});

Second, tighten Firestore security rules to enforce authentication and ownership. Rules should prevent unauthenticated access and ensure users can only modify their own documents.

For Firestore rules (version 2), a secure baseline looks like this:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
    match /sessions/{sessionId} {
      allow create: if request.auth != null;
      allow read, update, delete: if request.auth != null && request.auth.uid == request.resource.data.userId;
    }
  }
}

Third, in Koa route handlers, always verify that the requesting user matches the resource they are trying to access. Avoid trusting path parameters alone.

router.get('/profile/:userId', async (ctx) => {
  const requestingUserId = ctx.state.user?.uid; // from verified auth middleware
  const targetUserId = ctx.params.userId;
  if (!requestingUserId || requestingUserId !== targetUserId) {
    ctx.throw(403, 'Unauthorized');
  }
  const userDoc = await db.collection('users').doc(targetUserId).get();
  if (!userDoc.exists) {
    ctx.throw(404, 'User not found');
  }
  ctx.body = userDoc.data();
});

Finally, manage sessions with server-side storage in Firestore and short lifetimes. Store session metadata server-side and bind sessions to fingerprints where possible.

const uuid = require('uuid');

router.post('/login', async (ctx) => {
  const { email, password } = ctx.request.body;
  const userSnapshot = await db.collection('users').where('email', '==', email).limit(1).get();
  if (userSnapshot.empty) {
    ctx.throw(401, 'Invalid credentials');
  }
  const user = userSnapshot.docs[0].data();
  const passwordMatch = await bcrypt.compare(password, user.passwordHash);
  if (!passwordMatch) {
    ctx.throw(401, 'Invalid credentials');
  }
  const sessionId = uuid.v4();
  const sessionRef = db.collection('sessions').doc(sessionId);
  await sessionRef.set({
    userId: userSnapshot.id,
    createdAt: new Date(),
    expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
  });
  ctx.cookies.set('sessionId', sessionId, { httpOnly: true, secure: true, path: '/' });
  ctx.body = { message: 'Logged in' };
});

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

How does middleBrick assess authentication risks in a Koa and Firestore setup?
middleBrick runs 12 parallel security checks including Authentication, BOLA/IDOR, and Data Exposure. For a Koa app with Firestore, it inspects unauthenticated attack surfaces, validates Firestore rule strictness, and flags weak credential storage or overly permissive read/write permissions without requiring credentials or agents.
Can middleBrick test LLM security risks in APIs exposed by Koa services?
Yes. middleBrick’s unique LLM/AI Security checks include system prompt leakage detection, active prompt injection testing, output scanning for PII or API keys, and detection of excessive agency patterns. These checks apply to any unauthenticated LLM endpoints, including those integrated via Koa middleware.