HIGH security misconfigurationfeathersjsbasic auth

Security Misconfiguration in Feathersjs with Basic Auth

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

FeathersJS is a framework for real-time APIs that can expose HTTP and WebSocket transports. When Basic Authentication is used without additional protections, the framework’s default behavior and common integrations can create a security misconfiguration. This misconfiguration typically manifests in two dimensions of the API security assessment: Authentication and BOLA/IDOR (or Property Authorization).

In the Authentication check, the scanner evaluates whether the endpoint requires credentials and whether weak or default credentials are in use. If Basic Auth is implemented by reading credentials from environment variables but the server is also configured to allow unauthenticated access during development or testing, an attacker can reach production-like endpoints without credentials. This results in an Authentication misconfiguration finding because the effective authentication boundary is inconsistent.

In the BOLA/IDOR and Property Authorization checks, the framework’s REST-style resource mapping (e.g., /users/:id) can expose references to user identifiers in URLs. If the FeathersJS service does not enforce ownership checks after authentication, an attacker authenticated with a low-privilege Basic Auth credential can iterate over numeric or predictable IDs and access or modify other users’ data. This is a misconfiguration in how the application applies authorization after authentication, not a flaw in Basic Auth itself, but a failure to enforce proper scope checks.

Data Exposure is another relevant category. Basic Auth sends credentials in an RFC7617 header that is base64-encoded, not encrypted. If the FeathersJS API is served over HTTP instead of HTTPS, credentials are trivially recoverable. Even over HTTPS, if the API responses include sensitive fields (e.g., internal IDs, roles, or PII) and those responses are not explicitly limited by field-level authorization, the Data Exposure check will flag the endpoint. The scanner cross-references the OpenAPI spec, if available, against runtime behavior to confirm whether responses contain more data than declared.

An example of insecure code that can lead to this misconfiguration is a FeathersJS service that attaches the current user globally but does not validate that the authenticated user is allowed to access the requested resource:

const { AuthenticationError } = require('@feathersjs/errors');
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const app = express(feathers());

app.configure(express.rest());
app.configure(express.socketio());

// Basic Auth hook that attaches user but does not scope data access
app.hooks({
  before: {
    all: [async context => {
      const auth = context.params.headers && context.params.headers.authorization;
      if (auth && auth.startsWith('Basic ')) {
        const token = auth.slice(6);
        const user = Buffer.from(token, 'base64').toString('utf8');
        const [username] = user.split(':');
        context.params.user = { username };
      } else {
        throw new AuthenticationError('Unauthorized');
      }
      return context;
    }]
  }
});

app.use('/messages', {
  async find(params) {
    // Missing check that messages belong to params.user.username
    return [{ text: 'Hello', userId: 1 }, { text: 'Private', userId: 2 }];
  }
});

app.listen(3030);

In this setup, the misconfiguration arises because the hook authenticates but does not enforce that each record returned belongs to the authenticated user. A scanner testing unauthenticated surfaces may not detect this if the endpoint is open, but authenticated scans will show that data from other users is accessible, triggering BOLA/IDOR and Data Exposure findings mapped to OWASP API Top 10 and relevant compliance frameworks.

Basic Auth-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on two areas: ensuring transport security and enforcing per-request authorization. Always serve FeathersJS APIs over HTTPS so that Base64-encoded credentials are not exposed in transit. Then, scope data access to the authenticated user by validating ownership before returning records.

Below is a secure example that includes HTTPS redirection (when behind a proxy), strict Basic Auth parsing, and user-scoped data retrieval:

const { AuthenticationError } = require('@feathersjs/errors');
const feathers = require('@feathersjs/feathers');
const express = require('@feathersjs/express');
const app = express(feathers());

app.configure(express.rest());

// Enforce HTTPS in production by redirecting or rejecting non-secure traffic at the edge.
// This code assumes TLS termination is handled by a load balancer or reverse proxy.

// Secure Basic Auth hook with user scoping
app.hooks({
  before: {
    all: [async context => {
      const auth = context.params.headers && context.params.headers.authorization;
      if (!auth || !auth.startsWith('Basic ')) {
        throw new AuthenticationError('Unauthorized');
      }
      const token = auth.slice(6);
      const decoded = Buffer.from(token, 'base64').toString('utf8');
      const [username, password] = decoded.split(':');

      // Validate credentials against a secure store; this is a placeholder
      const validUser = await validateUser(username, password);
      if (!validUser) {
        throw new AuthenticationError('Invalid credentials');
      }

      // Attach a minimal user context without secrets
      context.params.user = { id: validUser.id, username: validUser.username };
      return context;
    }]
  }
});

// Example service with ownership check in the find method
app.use('/messages', {
  async find(params) {
    const currentUser = params.user;
    // Filter records so users only see their own messages
    return db.messages.findAll({ where: { userId: currentUser.id } });
  },
  async get(id, params) {
    const currentUser = params.user;
    const record = await db.messages.findByPk(id);
    if (!record || record.userId !== currentUser.id) {
      throw new NotFound('Message not found or access denied');
    }
    return record;
  }
});

async function validateUser(username, password) {
  // Implement secure lookup, e.g., using a constant-time comparison
  // and a hashed password store; this is a stub.
  return db.users.findByUsername(username);
}

app.listen(3030);

Key remediation steps encoded in the example:

  • Reject malformed or missing Basic Auth headers early with a clear AuthenticationError.
  • Parse the credential pair and validate the user against a secure backend; avoid using plaintext passwords in hooks.
  • Attach only the necessary user metadata (id, username) to the context, avoiding over-provisioning of permissions.
  • Apply per-method authorization (find, get) so that queries are filtered by the authenticated user’s identifier, preventing BOLA/IDOR across all transports.

When using the middleBrick CLI (middlebrick scan <url>) or the GitHub Action to add API security checks to your CI/CD pipeline, these corrected patterns will reduce findings in Authentication, BOLA/IDOR, Data Exposure, and Property Authorization categories, helping you maintain a lower risk score.

Frequently Asked Questions

Does middleBrick fix the misconfiguration it detects?
middleBrick detects and reports security misconfigurations with remediation guidance; it does not fix, patch, block, or remediate the issues.
Can the scanner validate ownership checks in FeathersJS services?
The scanner tests the unauthenticated attack surface and, when authenticated contexts are provided, can detect whether ownership checks are missing, mapping findings to BOLA/IDOR and Property Authorization checks.