HIGH prototype pollutionfeathersjs

Prototype Pollution in Feathersjs

How Prototype Pollution Manifests in Feathersjs

Prototype Pollution in Feathersjs occurs when untrusted user input modifies JavaScript object prototypes, creating security vulnerabilities through the framework's data handling patterns. Feathersjs's flexible service architecture and dynamic query building make it particularly susceptible to prototype pollution attacks.

The most common attack vector involves Feathersjs's params.query object, which automatically parses URL query parameters into JavaScript objects. When users send parameters like __proto__.isAdmin=true, these properties get assigned to the prototype chain rather than the intended object, affecting all instances.

// Vulnerable Feathersjs service endpoint
app.get('/users', async (req, res) => {
  const params = req.feathers || {};
  
  // __proto__.isAdmin=true gets assigned to Object.prototype
  // Now every object has isAdmin: true
  const isAdmin = params.query?.isAdmin || false;
  
  // This check fails because isAdmin is now true on all objects
  if (!isAdmin) {
    return res.status(403).json({ error: 'Forbidden' });
  }
  
  const users = await userService.find(params);
  return res.json(users);
});

Another critical pattern involves Feathersjs's patch and update operations. The framework's data validation occurs after prototype pollution has already compromised the object structure:

// Vulnerable patch operation
app.patch('/users/:id', async (req, res) => {
  const { id } = req.params;
  const data = req.feathers?.data || {};
  
  // If data contains __proto__.role='admin', it affects all users
  await userService.patch(id, data, req.feathers);
  return res.json({ success: true });
});

Feathersjs's hook system can also propagate prototype pollution through context.params. Hooks often merge user input without proper sanitization:

// Vulnerable hook
const vulnerableHook = async context => {
  // Merges user input directly into params
  context.params = { ...context.params, ...context.data };
  return context;
};

The framework's MongoDB adapter is particularly vulnerable because it directly uses query objects for database operations. Prototype pollution can bypass authorization checks by adding properties to the prototype chain that affect query results globally.

Feathersjs-Specific Detection

Detecting Prototype Pollution in Feathersjs requires examining both runtime behavior and static code patterns. The most effective approach combines automated scanning with manual code review.

middleBrick's API security scanner includes specialized detection for Prototype Pollution patterns in Feathersjs applications. The scanner examines request handling patterns, hook implementations, and data validation logic to identify vulnerable code paths.

# Scan a Feathersjs API endpoint
middlebrick scan https://api.example.com/users

# Results show Prototype Pollution findings with severity and
# specific code locations where the vulnerability exists

Manual detection should focus on these Feathersjs-specific patterns:

  • Direct assignment of req.feathers.data without validation
  • Use of Object.assign() or spread operators on user input
  • Hook chains that merge context.params with untrusted data
  • Query parameter parsing without prototype pollution protection

Static analysis tools can identify risky patterns in Feathersjs codebases:

// Dangerous patterns to flag
const dangerousPatterns = [
  'Object.assign(context.params, user_input)',
  '{ ...context.params, ...user_input }',
  'req.feathers.data',
  'params.query.__proto__'
];

Runtime detection involves logging and monitoring for unusual object property assignments. Feathersjs applications should log prototype modifications and alert on suspicious patterns.

Feathersjs-Specific Remediation

Remediating Prototype Pollution in Feathersjs requires a defense-in-depth approach using the framework's built-in security features and careful input handling.

The most effective protection is using Object.create(null) for objects that will contain user input:

// Secure pattern for query parameters
app.get('/users', async (req, res) => {
  const safeParams = Object.create(null);
  
  // Only allow specific properties
  const allowed = ['page', 'limit', 'search'];
  for (const key of allowed) {
    if (req.query[key] !== undefined) {
      safeParams[key] = req.query[key];
    }
  }
  
  const users = await userService.find({ query: safeParams });
  return res.json(users);
});

Feathersjs's hook system provides excellent protection points. Create a prototype pollution prevention hook:

// Prototype pollution prevention hook
const preventPrototypePollution = async context => {
  const sanitize = obj => {
    if (obj === null || typeof obj !== 'object') return obj;
    
    if (Array.isArray(obj)) {
      return obj.map(sanitize);
    }
    
    const cleaned = Object.create(null);
    for (const [key, value] of Object.entries(obj)) {
      if (key.startsWith('__proto__') || key.includes('.__proto__')) {
        throw new Error('Prototype pollution attempt detected');
      }
      cleaned[key] = sanitize(value);
    }
    return cleaned;
  };
  
  context.data = sanitize(context.data);
  context.params.query = sanitize(context.params.query);
  return context;
};

// Apply globally
app.hooks({
  before: {
    all: [preventPrototypePollution]
  }
});

For Feathersjs services, use the whitelist option to restrict allowed properties:

// Secure service definition
app.service('users').hooks({
  before: {
    create: [sanitizeData(['name', 'email', 'role'])],
    patch: [sanitizeData(['name', 'email'])],
    update: [sanitizeData(['name', 'email', 'role'])]
  }
});

Implement comprehensive input validation using libraries like joi or zod with strict schemas:

import { z } from 'zod';

const userSchema = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  role: z.enum(['user', 'admin']).optional()
});

const validateInput = async context => {
  try {
    context.data = userSchema.parse(context.data);
  } catch (error) {
    throw new Error('Invalid input data');
  }
  return context;
};

Enable prototype pollution protection in your Feathersjs configuration by setting Object.freeze(Object.prototype) during application startup, though this may affect third-party libraries.

Frequently Asked Questions

How does middleBrick detect Prototype Pollution in Feathersjs applications?
middleBrick scans Feathersjs APIs by examining request handling patterns, hook implementations, and data validation logic. The scanner looks for vulnerable patterns like direct assignment of req.feathers.data, use of Object.assign() on user input, and hook chains that merge context.params with untrusted data. It tests for prototype pollution by sending specially crafted payloads and analyzing the application's response behavior.
Can Prototype Pollution affect Feathersjs's database operations?
Yes, Prototype Pollution can severely impact Feathersjs's database operations, especially with MongoDB adapters. When prototype properties are added to query objects, they can affect all database queries globally, bypassing authorization checks and exposing data across all users. This occurs because MongoDB drivers use the entire query object for database operations, including any prototype properties that have been polluted.