HIGH api key exposurefeathersjsmongodb

Api Key Exposure in Feathersjs with Mongodb

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

FeathersJS is a framework for creating JavaScript APIs with services that map to MongoDB collections. When an API key or similar long-lived credential is stored in a MongoDB collection and that collection is exposed as a FeathersJS service without proper controls, the key can be read, leaked, or exfiltrated through common API patterns.

Consider a keys collection storing service credentials. If you define a Feathers service with a minimal find configuration and do not restrict paginate or multi, or if you allow authentication rules that are too permissive, an unauthenticated or low-privilege caller may enumerate or retrieve the key documents. For example:

const keysService = app.service('keys');
// Risky: no server-side filtering or authorization on find
keysService.find({ query: { $limit: 100 } }).then(result => {
  console.log(result.data);
});

If the service allows find for everyone (e.g., hooks: { before: { all: [] } } with no policy checks), an attacker can enumerate keys. Additionally, if the API returns full documents including the key field because the schema does not explicitly exclude it, the key is exposed in responses.

FeathersJS MongoDB adapters typically map service queries directly to MongoDB operations. Without explicit projection to remove sensitive fields, or without server-side field-level filtering, a query like { $select: ['name', 'key'] } or an empty $select can return the key. Also, improper use of params.query allows injection of additional MongoDB operators that may inadvertently expose more data than intended.

The risk is compounded when combined with other checks: weak or missing authentication, overly broad roles, or misconfigured CORS. An attacker may also probe for IDOR (Broken Object Level Authorization) across the keys service if numeric or ObjectId identifiers are predictable, leading to horizontal privilege escalation where one user can read another’s key records.

Another vector is logging or error handling that echoes query parameters or stack traces containing key values. If your Feathers app logs full params or MongoDB responses, keys can be exposed in logs or to an LLM endpoint if client-supplied data is forwarded without scrubbing.

To detect this pattern, a scanner would look for:

  • Feathers services on collections that plausibly store credentials (e.g., named keys, credentials, tokens)
  • Unrestricted find permissions in service configuration or hooks
  • Missing projection or field filtering that allows key fields to travel in responses
  • Inadequate authentication on service methods, especially for read operations

Mongodb-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on service configuration, hooks, and query handling to ensure MongoDB documents containing keys are never returned unintentionally.

1) Use field-level filtering to exclude sensitive fields. In your service definition, explicitly set paginate and use a hook to remove the key field from responses:

// src/services/keys/keys.hooks.js
const { iff, isProvider } = require('feathers-hooks-common');

exports.removeSecrets = () => async context => {
  // Remove the 'key' field from responses for all providers (REST, SocketIO)
  if (Array.isArray(context.result.data)) {
    context.result.data.forEach(item => { if (item) delete item.key; });
  } else if (context.result.data && typeof context.result.data === 'object') {
    delete context.result.data.key;
  }
  return context;
};

// src/services/keys/keys.service.js
const keysService = require('feathers-mongodb');
const hooks = require('./keys.hooks');

app.use('/keys', keysService({
  Model: app.get('mongodb').collection('keys'),
  paginate: { default: 10, max: 10 },
  hooks: {
    before: {
      all: [],
    },
    after: {
      all: [hooks.removeSecrets()],
    },
  },
}));

2) Restrict find to authenticated callers and apply strict roles. Require authentication and use a custom hook to enforce that callers can only access their own key records (if applicable), or restrict find to admin roles only:

// src/services/keys/keys.hooks.js
const authenticate = require('feathers-authentication').hook;
const { iff, isProvider, preventChanges } = require('feathers-hooks-common');
const { discard } = require('feathers-hooks-common');

const restrictToAdmin = context => {
  const { user } = context.params;
  if (!user || !user.isAdmin) {
    throw new Error('Unauthorized');
  }
  return context;
};

exports.before = {
  all: [authenticate()],
  find: [restrictToAdmin],
  get: [restrictToAdmin],
};

3) Control MongoDB query operators to prevent injection or over-fetching. Sanitize params.query to remove unexpected operators and enforce projection:

const sanitizeQuery = require('feathers-mongodb/lib/sanitize-query');

exports.sanitizeMongoQuery = () => async context =>
{
  const { originalQuery, query } = sanitizeQuery(context.params.query);
  // Explicitly project only safe fields
  query.$project = { name: 1, type: 1, createdAt: 1 };
  context.params.query = { ...query };
  return context;
};

// Apply in service hooks
app.use('/keys', keysService({
  Model: app.get('mongodb').collection('keys'),
  hooks: {
    before: {
      all: [hooks.sanitizeMongoQuery()],
    },
  },
}));

4) Store keys outside of MongoDB user collections when possible. Use environment variables or a dedicated secrets manager, and reference them via service configuration rather than storing raw values in database rows. If you must store in MongoDB, ensure encryption at rest is enabled on the database side and that backups are also protected.

5) Audit and monitor. Add a hook that logs access to sensitive services and review patterns. Combine with runtime security tooling that can flag anomalous queries against the keys collection.

Frequently Asked Questions

Can a FeathersJS MongoDB service expose API keys if authentication is disabled?
Yes. If a Feathers service on a MongoDB collection has no authentication or authorization hooks, and find is allowed publicly, documents containing API keys can be enumerated and read by unauthenticated clients.
How can I verify that key fields are not returned in API responses?
Use the CLI to scan your API (e.g., middlebrick scan ) and review the Data Exposure findings; also inspect network responses in your browser’s dev tools to confirm sensitive fields like key or secret are absent.