HIGH api key exposurefeathersjsfirestore

Api Key Exposure in Feathersjs with Firestore

Api Key Exposure in Feathersjs with Firestore — how this specific combination creates or exposes the vulnerability

FeathersJS is a framework for creating JavaScript APIs with real-time capabilities. When it uses Google Cloud Firestore as a service adapter, developers may inadvertently expose API keys or service account credentials through service initialization or request handling. A typical vulnerable pattern is initializing Firestore with a key file path accessible to the application process and then attaching that client to the Feathers service without restricting access at the API layer.

Consider a Feathers service that creates a Firestore client using a key file stored on disk:

const { Firestore } = require('@google-cloud/firestore');
const app = require('feathers')();
const service = require('feathers-firestore');

const firestore = new Firestore({
  keyFilename: '/path/to/service-account.json'
});

app.use('/todos', service({
  db: firestore,
  collection: 'todos'
}));

If the service account JSON file is readable by the runtime user and the Firestore client is passed directly into the Feathers service, any API endpoint that returns a document may leak sensitive metadata associated with the service account. An attacker who compromises the API endpoint or reads server-side logs might infer the location of the key file or observe error messages that contain project identifiers.

Moreover, if the Feathers application is misconfigured to expose the Firestore client or its configuration through introspection endpoints or debug routes, an API key embedded in the client configuration could be enumerated. For example, a developer might accidentally serialize the Firestore client for debugging:

app.hooks({
  after: {
    all() {
      return {
        firestoreConfig: this.firestore?.settings?.credentials
      };
    }
  }
});

Such a hook would expose credential details in API responses, turning what should be a backend-only client into a data exposure vector. Firestore does not rotate keys automatically in this scenario; if a key is exposed, the associated project permissions remain valid until manual rotation occurs.

Another exposure route arises when environment variables that point to key file paths are printed or logged. Feathers applications often rely on environment-based configuration, and if a startup script logs the full configuration object, an API key path or project ID may be written to stdout, which could be captured by log aggregation systems with broader access controls.

Because middleBrick tests the unauthenticated attack surface, it can detect endpoints that return configuration objects or error details that reference project IDs or credential scopes. Findings are mapped to relevant frameworks and compliance controls, such as OWASP API Top 10 and SOC2, to help prioritize remediation.

Firestore-Specific Remediation in Feathersjs — concrete code fixes

To mitigate exposure, initialize Firestore with least-privilege credentials and avoid attaching sensitive objects to the Feathers application context. Use environment variables to reference key file locations, and ensure that no runtime hooks expose client settings.

Instead of referencing a key file directly in service initialization, rely on Application Default Credentials (ADC) when running in Google Cloud environments, or explicitly limit the scopes available to the client:

const { Firestore } = require('@google-cloud/firestore');
const app = require('feathers')();
const service = require('feathers-firestore');

const firestore = new Firestore({
  projectId: process.env.FIRESTORE_PROJECT_ID,
  // Omit keyFilename; rely on ADC or explicitly scoped credentials
  // scopes: ['https://www.googleapis.com/auth/datastore']
});

app.use('/todos', service({
  db: firestore,
  collection: 'todos'
}));

If a key file must be used, store it outside the application directory and restrict filesystem permissions. Never commit the file to version control. You can also create a restricted service account in Google Cloud IAM and grant only the Firestore read permissions required for the operation.

To prevent accidental serialization, remove any hooks that expose client configuration and validate that responses do not include sensitive metadata:

// Remove or secure debug hooks that might expose configuration
// Avoid hooks like:
// app.hooks({
//   after: {
//     all() {
//       return { firestoreConfig: this.firestore?.settings?.credentials };
//     }
//   }
// });

// Instead, use health checks that do not expose internals:
app.get('/health', () => ({
  status: 'ok'
}));

When using the middleBrick CLI to scan this setup, you can verify that endpoints do not return configuration objects and that Firestore initialization does not leak project identifiers in error responses:

middlebrick scan https://your-api.example.com

The CLI produces a structured report that highlights potential exposure points, and the Web Dashboard allows you to track changes over time. For teams requiring automated enforcement, the Pro plan’s GitHub Action can fail builds if a scan detects insecure service initialization patterns, while the MCP Server enables scanning directly from AI coding assistants within your development environment.

Finally, rotate service account keys regularly and monitor IAM policy changes. Even with code fixes, ongoing credential hygiene is essential to reduce the window of exposure. These steps align with best practices for API security and help ensure that Firestore integration remains resilient against inadvertent key disclosure.

Frequently Asked Questions

How can I verify that my FeathersJS API does not expose Firestore credentials in responses?
Use the middleBrick CLI to scan your endpoints: middlebrick scan . Review the report for any findings related to configuration exposure or error messages that reference project IDs or credential scopes.
Is it safe to store the service account JSON file in the same repository as my FeathersJS code?
No. Storing service account JSON files in the same repository increases the risk of accidental exposure through version control. Use environment variables or Google Cloud IAM roles to manage credentials instead.