HIGH broken authenticationfeathersjsfirestore

Broken Authentication in Feathersjs with Firestore

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

FeathersJS is a minimal, extensible framework for creating JavaScript APIs with real-time capabilities. When used with Google Cloud Firestore as the persistence layer, authentication correctness depends on how the service is configured and how hooks validate identity and permissions. Broken Authentication occurs when identity verification is incomplete, tokens are mishandled, or authorization checks are missing, enabling attackers to impersonate users or escalate privileges.

In a FeathersJS + Firestore setup, common root causes include missing authentication on service hooks, trusting client-supplied user IDs, and failing to validate ID tokens server-side. For example, a Feathers service that uses only authentication: false or relies solely on client-provided parameters is vulnerable to direct object reference attacks. Attackers can modify resource IDs in requests to access other users' data, especially when the service does not enforce ownership checks against Firestore documents.

Firestore security rules are not a substitute for server-side authorization in FeathersJS. Rules protect data at the database level but do not enforce application-level business logic or identity validation. If a Feathers service does not explicitly verify the authenticated user's identity and permissions, an attacker with a valid session token (or a stolen token) can traverse relationships in Firestore by manipulating IDs in payloads or URLs. This is a classic Broken Authentication vector (OWASP API Top 10:2023 API1:2023 Broken Object Level Authorization).

Token handling issues exacerbate the risk. FeathersJS supports multiple authentication strategies, including JWT. If JWT secrets are weak, tokens are not validated properly, or tokens are accepted without signature verification, an attacker can forge tokens. Real-world incidents involving weak JWT configurations have been tracked in the CVE ecosystem, where missing or incorrect verification allowed account takeover. Additionally, if your Feathers app exposes an unauthenticated endpoint that returns sensitive data or accepts state-changing requests, it effectively bypasses identity checks.

Excessive agency patterns can also appear when integrating with AI-assisted tooling. An LLM endpoint used for code suggestions might inadvertently expose authentication logic or accept unsafe inputs that affect identity checks. While this does not introduce new classes of vulnerability, it highlights the importance of validating every input path, including those influenced by generated code.

To detect these issues, security scanners perform unauthenticated and authenticated tests across the attack surface, checking whether services correctly require authentication, validate object ownership, and enforce least privilege. Proper remediation requires explicit server-side checks, secure token validation, and strict Firestore document-level ownership verification.

Firestore-Specific Remediation in Feathersjs — concrete code fixes

Remediation centers on enforcing authentication on every relevant service hook, validating identity server-side, and ensuring Firestore queries are scoped to the authenticated user. Below are concrete, working examples for a FeathersJS service using the Firebase Admin SDK.

First, initialize the Firebase Admin SDK and configure Feathers authentication. This example uses JWT strategy, but the principles apply to other strategies as well.

const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const authentication = require('@feathersjs/authentication');
const jwt = require('@feathersjs/authentication-jwt');
const admin = require('firebase-admin');

admin.initializeApp({
  credential: admin.credential.applicationDefault(),
});

const app = express(feathers());

app.configure(authentication({
  secret: 'your_jwt_secret',
  entity: 'user',
  service: 'users',
}));

app.use('/messages', express.service({
  async find(params) {
    const { user } = params;
    if (!user || !user._id) {
      throw new Error('Unauthenticated');
    }
    const snapshot = await admin.firestore().collection('messages')
      .where('ownerId', '==', user._id)
      .get();
    const messages = [];
    snapshot.forEach(doc => messages.push({ id: doc.id, ...doc.data() }));
    return messages;
  },

  async get(id, params) {
    const { user } = params;
    if (!user || !user._id) {
      throw new Error('Unauthenticated');
    }
    const doc = await admin.firestore().collection('messages').doc(id).get();
    if (!doc.exists) {
      throw new Error('Not found');
    }
    const data = doc.data();
    if (data.ownerId !== user._id) {
      throw new Error('Forbidden: ownership mismatch');
    }
    return { id: doc.id, ...data };
  },

  async create(data, params) {
    const { user } = params;
    if (!user || !user._id) {
      throw new Error('Unauthenticated');
    }
    const docRef = await admin.firestore().collection('messages').add({
      ...data,
      ownerId: user._id,
      createdAt: admin.firestore.FieldValue.serverTimestamp(),
    });
    return { id: docRef.id, ...data, ownerId: user._id };
  },
}));

app.use('messages', authentication.hooks({
  authenticate: ['jwt'],
}));

Key points in this setup:

  • Authentication is explicitly required on the service via authenticate: ['jwt'].
  • Each hook validates params.user before proceeding, ensuring the request has a verified identity.
  • Firestore queries use where('ownerId', '==', user._id) to enforce ownership at query time, preventing enumeration across users.
  • Create operations bind ownerId to the authenticated user server-side, ignoring any client-supplied value.

Additionally, ensure your Firebase project uses robust JWT secret rotation and that tokens are transmitted over HTTPS only. Monitor for unusual access patterns using Firebase logs and integrate alerts for anomalous reads or writes.

For continuous protection, the Pro plan enables continuous monitoring and can integrate with GitHub Actions to fail builds if security scores degrade. The dashboard and MCP Server provide visibility and developer context without changing your runtime behavior.

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

Why aren't Firestore security rules enough to prevent Broken Authentication in FeathersJS?
Firestore security rules protect data at the storage layer but do not enforce application-level identity validation or business logic. FeathersJS services must explicitly authenticate requests and scope queries to the authenticated user; rules alone cannot prevent ID manipulation or missing authentication checks in your service code.
Can client-supplied user IDs be trusted if Firestore rules restrict writes to ownerId?
No. Client-supplied IDs should never be trusted for authorization. Always derive the user identity from a verified server-side source (e.g., params.user from an authenticated JWT) and use server-side fields like ownerId in queries and writes to enforce ownership.