HIGH security misconfigurationfeathersjsfirestore

Security Misconfiguration in Feathersjs with Firestore

Security Misconfiguration in Feathersjs with Firestore — how this specific combination creates or exposes the vulnerability

FeathersJS is a framework for real-time applications that commonly integrates with Google Cloud Firestore as a data store. When Firestore security rules are not aligned with FeathersJS service configurations, Security Misconfiguration vulnerabilities emerge. This occurs when rules are permissive (e.g., allowing read/write to all authenticated users or to anyone), when rules fail to validate resource ownership, or when FeathersJS services do not enforce authorization checks before passing requests to Firestore.

Consider a FeathersJS service defined without explicit authorization checks and relying on default or open Firestore rules:

// services/messages/messages.class.js
const { Service } = require('feathersjs-sequelize');
class MessageService extends Service {
  async create(data, params) {
    // If Firestore rules allow broad access, this may write without ownership checks
    return super.create(data, params);
  }
}
module.exports = function (app) {
  app.use('/messages', new MessageService({ Model: app.get('sequelize').models.messages, paginate: { default: 25 } }));
};

If the corresponding Firestore rules are:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /messages/{document} {
      allow read, write: if true; // Overly permissive
    }
  }
}

Any client authenticated by FeathersJS can read or write any message, leading to mass data exposure or unauthorized modification. This is a Security Misconfiguration because the service does not enforce scoping (e.g., user-specific document ownership) and the rules do not enforce the principle of least privilege.

A more targeted risk arises when Firestore rules validate user identity but FeathersJS services do not consistently apply the same ownership checks. For example, if a rule uses request.auth.uid but the FeathersJS service method does not verify that the resource belongs to the requesting user, an IDOR (Insecure Direct Object Reference) can be chained with misconfigured rules to allow horizontal privilege escalation.

Additionally, Firestore rules that allow creation without validating required fields or data types can lead to inconsistent or malicious data states when FeathersJS services accept untrusted input. For instance, a rule that permits writes without checking for a userId field may allow clients to escalate privileges by assigning themselves admin roles if the application logic relies on that field later.

Because middleBrick tests the unauthenticated attack surface and maps findings to frameworks like OWASP API Top 10, such misconfigurations are flagged with remediation guidance to align service behavior with least-privilege Firestore rules and consistent authorization in FeathersJS.

Firestore-Specific Remediation in Feathersjs — concrete code fixes

Remediation centers on tightening Firestore rules to match the access patterns of your FeathersJS services and adding explicit authorization in service methods.

1) Scope rules to authenticated user UID and enforce ownership

Update Firestore rules to scope writes to the authenticated user’s UID and reads to documents they own or are shared with. Combine this with FeathersJS hooks to ensure request context is available for rule evaluation:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /messages/{document} {
      allow read: if request.auth != null && request.auth.uid == request.resource.data.userId;
      allow write: if request.auth != null && request.auth.uid == request.resource.data.userId;
    }
  }
}

2) FeathersJS service with hook-based authorization

In FeathersJS, use a before hook to inject the user ID and enforce ownership before the service interacts with Firestore. This ensures the service does not rely solely on rules for scoping:

// src/hooks/userIdFromAuth.hooks.js
const ensureUserContext = context => {
  if (context.params.auth && context.params.auth.uid) {
    context.params.userId = context.params.auth.uid;
  } else {
    throw new Error('Unauthenticated');
  }
  return context;
};
module.exports = { ensureUserContext };
// services/messages/messages.class.js
const { Service } = require('feathersjs-sequelize');
const { ensureUserContext } = require('./userIdFromAuth.hooks');
class MessageService extends Service {
  async create(data, params) {
    // Ensure userId is present and matches the authenticated user
    if (!params.userId || params.userId !== params.auth?.uid) {
      throw new Error('Forbidden: user ID mismatch');
    }
    data.userId = params.userId;
    return super.create(data, params);
  }
}
module.exports = function (app) {
  const service = new MessageService({ Model: app.get('sequelize').models.messages, paginate: { default: 25 } });
  service.before({ create: [ensureUserContext] });
  app.use('/messages', service);
};

3) Validate input and align rule conditions with service logic

Ensure Firestore rules validate required fields and data shapes, and that FeathersJS services validate input before persistence. For example, enforce userId presence and type in both rule and service:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /messages/{document} {
      allow create: if request.auth != null
        && request.resource.data.userId is string
        && request.resource.data.userId == request.auth.uid
        && request.resource.data.text is string
        && request.resource.data.createdAt is timestamp;
      allow update: if request.auth != null
        && request.resource.data.userId == request.auth.uid;
    }
  }
}

Corresponding FeathersJS validation (using AJV or similar) ensures only valid payloads reach Firestore, reducing rule bypass risk:

// src/validators/message.validator.js
const ajv = require('ajv')();
const schema = {
  type: 'object',
  required: ['text'],
  properties: {
    text: { type: 'string', minLength: 1 },
    userId: { type: 'string' }
  }
};
const validate = ajv.compile(schema);
module.exports = context => {
  if (!validate(context.data)) {
    throw new Error(`Invalid input: ${validate.errors.map(e => e.message).join(', ')}`);
  }
  return context;
};

By combining least-privilege Firestore rules with FeathersJS service hooks and input validation, you reduce the attack surface and align security across the stack. middleBrick’s scans can detect overly permissive rules and missing service-side checks, providing prioritized findings with remediation guidance.

Frequently Asked Questions

How does middleBrick detect Security Misconfiguration in Feathersjs with Firestore?
middleBrick runs 12 parallel checks including Authentication, BOLA/IDOR, Property Authorization, and Input Validation against the unauthenticated attack surface. It cross-references OpenAPI/Swagger specs with runtime behavior and flags overly permissive Firestore rules or missing service-side authorization in FeathersJS services, providing severity-ranked findings and remediation guidance.
Can middleBrick test Firestore rules without credentials?
Yes. middleBrick scans the unauthenticated attack surface by default. It probes endpoints and rule-like behaviors where applicable and reports misconfigurations such as public read/write or missing ownership constraints without requiring API keys or tokens.