HIGH vulnerable componentsfeathersjscockroachdb

Vulnerable Components in Feathersjs with Cockroachdb

Vulnerable Components in Feathersjs with Cockroachdb — how this specific combination creates or exposes the vulnerability

FeathersJS is a framework for creating JavaScript APIs with services centered around CRUD operations. When FeathersJS applications connect to CockroachDB, a distributed SQL database, specific patterns in query construction and data handling can expose components to common API security risks such as IDOR, mass assignment, and injection. These vulnerabilities arise from a mismatch between FeathersJS service flexibility and CockroachDB schema constraints or from insufficient validation before queries are issued.

One vulnerable component is the dynamic query builder used by FeathersJS adapters. If a FeathersJS service for a users entity builds WHERE clauses by directly interpolating request query parameters into SQL-like conditions without strict allowlisting, an attacker can manipulate filters to access other users’ records. For example, a request like /[email protected] could be altered to /[email protected]&$or[0][id]=$eq&0 to bypass intended isolation when CockroachDB returns broader results due to permissive adapter configuration.

Another component is the lack of strict schema enforcement for nested objects. FeathersJS services often accept JSON payloads for create or patch operations. If these payloads are mapped directly to CockroachDB columns without validation, an attacker can inject unexpected fields such as isAdmin or role to escalate privileges. This becomes dangerous when CockroachDB columns like role are used in row-level security (RLS) policies; improperly validated input can bypass intended access controls.

Input validation gaps also manifest in the handling of array and JSONB fields. CockroachDB supports JSONB columns, and FeathersJS services that accept arbitrary JSON objects may forward unsanitized arrays or objects into queries. Without proper sanitization, this can lead to injection-like behavior or unexpected data exposure when combined with CockroachDB’s JSON operators. For instance, a malformed JSON payload could cause the service to retrieve or modify unintended rows if the adapter does not enforce type and structure checks.

Finally, insufficient rate limiting and unauthenticated endpoint exposure in the FeathersJS service layer can amplify the impact of vulnerable components. If a /users service is publicly accessible and lacks robust rate limits, an attacker can conduct enumeration attacks against CockroachDB to infer valid user IDs or exploit IDOR patterns at scale. These design-level interactions between FeathersJS service definitions and CockroachDB access patterns create a chain that can lead to data exposure or privilege escalation.

Cockroachdb-Specific Remediation in Feathersjs — concrete code fixes

Remediation focuses on strict validation, parameterized queries, and schema-aware data handling. Below are concrete code examples for a FeathersJS service connected to CockroachDB.

1. Use parameterized queries with explicit field allowlisting

Ensure that query parameters are never directly interpolated. Use FeathersJS hooks to sanitize and parameterize inputs before they reach the adapter.

// src/hooks/validate-user-query.js
module.exports = function validateUserQuery() {
  return function(context) {
    const { email, $limit, $skip } = context.params.query;
    const allowedFields = ['email', 'status'];
    const filteredQuery = { $limit: Number($limit) || 10, $skip: Number($skip) || 0 };
    if (email) {
      if (!/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(email)) {
        throw new Error('Invalid email format');
      }
      filteredQuery.email = email;
    }
    // Explicitly allow only safe fields
    Object.keys(context.params.query).forEach(key => {
      if (allowedFields.includes(key)) {
        filteredQuery[key] = context.params.query[key];
      }
    });
    context.params.query = filteredQuery;
    return context;
  };
};

// In service definition (src/services/users/users.service.js)
const { Service } = require('feathersjs-sequelize');
const validateUserQuery = require('./hooks/validate-user-query');

class UserService extends Service {
  async find(params) {
    const query = params.query || {};
    // Use parameterized conditions for CockroachDB
    const where = {};
    if (query.email) where.email = query.email;
    const users = await this.Model.findAll({
      where,
      limit: Number(query.$limit) || 10,
      offset: Number(query.$skip) || 0
    });
    return { total: users.length, data: users };
  }
}

module.exports = function() {
  const app = this;
  app.use('/users', new UserService({
    Model: app.get('knex'), // configured for CockroachDB
    paginate: { default: 10, max: 50 }
  }));
  const userService = app.service('users');
  userService.hooks({
    before: {
      all: [validateUserQuery()],
      find: []
    }
  });
};

2. Strict schema validation for create/patch payloads

Define an allowlisted set of fields and types for each operation to prevent privilege escalation via unexpected fields.

// src/hooks/validate-payload.js
const allowedCreateFields = ['email', 'name', 'status'];
const allowedPatchFields = ['name', 'status'];

module.exports = function validatePayload() {
  return function(context) {
    const data = context.data || {};
    const isPatch = context.method === 'patch';
    const allowed = isPatch ? allowedPatchFields : allowedCreateFields;
    const filtered = {};
    Object.keys(data).forEach(key => {
      if (allowed.includes(key)) {
        if (key === 'email' && !/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(data[key])) {
          throw new Error('Invalid email');
        }
        filtered[key] = data[key];
      }
    });
    context.data = filtered;
    return context;
  };
};

// Usage in service
app.use('/users', new UserService({ /* options */ }));
app.service('users').hooks({
  before: {
    create: [validatePayload()],
    patch: [validatePayload()]
  }
});

3. Enforce row-level security via hooks

Use hooks to scope queries to the requesting user, ensuring that even if IDOR patterns exist, data access is limited.

// src/hooks/user-scope.js
module.exports = function userScope() {
  return function(context) {
    if (context.params.user && context.params.user.id) {
      context.params.query = context.params.query || {};
      context.params.query.userId = context.params.user.id;
    }
    return context;
  };
};

// Ensure your CockroachDB table has a userId column and RLS policy
// Example RLS policy (run in CockroachDB):
// CREATE POLICY "users_own_data" ON users FOR ALL
//   USING (auth_role() = 'authenticated' AND user_id = current_setting('app.user_id')::INT);

4. Sanitize JSONB and array inputs

Validate the structure of JSONB inputs to prevent unexpected queries or execution paths.

// src/hooks/validate-json-body.js
module.exports = function validateJsonBody() {
  return function(context) {
    const data = context.data || {};
    if (data.metadata && typeof data.metadata === 'object') {
      // Ensure metadata keys are alphanumeric
      Object.keys(data.metadata).forEach(key => {
        if (!/^[a-zA-Z0-9_-]+$/.test(key)) {
          throw new Error('Invalid metadata key');
        }
      });
    }
    context.data = data;
    return context;
  };
};

5. Apply rate limiting and authentication checks

Use FeathersJS hooks to enforce rate limits and ensure endpoints are not unintentionally public.

// src/hooks/rate-limit.js
const rateLimitMap = new Map();

module.exports = function rateLimit() {
  return function(context) {
    const ip = context.params.ip || 'unknown';
    const now = Date.now();
    const window = 60000; // 1 minute
    const maxRequests = 100;
    if (!rateLimitMap.has(ip)) {
      rateLimitMap.set(ip, []);
    }
    const timestamps = rateLimitMap.get(ip).filter(t => now - t < window);
    if (timestamps.length >= maxRequests) {
      throw new Error('Rate limit exceeded');
    }
    timestamps.push(now);
    rateLimitMap.set(ip, timestamps);
    return context;
  };
};

// Apply to public services
app.service('public-data').hooks({
  before: {
    all: [rateLimit()]
  }
});

Frequently Asked Questions

How does middleBrick detect IDOR vulnerabilities when scanning a FeathersJS API backed by CockroachDB?
middleBrick runs unauthenticated black-box checks that manipulate query parameters and observe whether the API returns data belonging to other users. For FeathersJS services using CockroachDB, it tests filter injection and missing row-level scope to identify IDOR patterns without relying on internal implementation details.
Can middleBrick scan an OpenAPI spec for a FeathersJS service and map findings to CockroachDB-specific risks?
Yes. middleBrick analyzes OpenAPI/Swagger specs (2.0, 3.0, 3.1) with full $ref resolution and cross-references definitions with runtime findings. This helps identify mismatches between declared parameters and actual query behavior when interacting with CockroachDB.