HIGH insecure direct object referencefeathersjs

Insecure Direct Object Reference in Feathersjs

How Insecure Direct Object Reference Manifests in Feathersjs

Insecure Direct Object Reference (IDOR) in Feathersjs typically occurs when applications expose internal object identifiers and rely on client-side access controls. Feathersjs's flexible service architecture and dynamic routing can create multiple attack vectors if proper authorization isn't implemented.

The most common IDOR pattern in Feathersjs involves service methods that accept ID parameters without validating whether the requesting user owns or has permission to access the resource. Consider this vulnerable Feathersjs service:

const { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication');
const { LocalStrategy } = require('@feathersjs/authentication-local');

class UsersService {
  async get(id, params) {
    // Vulnerable: no ownership check
    return this._super(id, params);
  }

  async update(id, data, params) {
    // Vulnerable: any authenticated user can update any user
    return this._super(id, data, params);
  }

  async remove(id, params) {
    // Vulnerable: any authenticated user can delete any user
    return this._super(id, params);
  }
}

The core issue is that Feathersjs services automatically handle CRUD operations without built-in authorization checks. A malicious user can simply modify the ID parameter in API requests to access other users' data.

Another Feathersjs-specific IDOR pattern occurs with params.query objects. Attackers can manipulate query parameters to bypass filters:

// Vulnerable: query parameter manipulation
app.service('messages').find({
  query: { userId: req.user.id }
});

// Attacker can modify request to:
app.service('messages').find({
  query: { userId: 'malicious-user-id' }
});

Feathersjs's hooks system, while powerful, can also introduce IDOR vulnerabilities if hooks aren't properly chained. A common mistake is applying authentication hooks but forgetting authorization hooks:

// Vulnerable hook chain
{
  before: {
    all: [ authenticate('jwt') ],
    get: [],
    update: []
  }
}

// Missing: authorization hooks to verify resource ownership

Feathersjs's population feature can also create IDOR risks. When services automatically populate related data, attackers might access relationships they shouldn't see:

// Vulnerable: automatic population without access control
app.service('posts').get(id, {
  populate: 'comments'
});

// Attacker could access comments on posts they don't own

Feathersjs-Specific Detection

Detecting IDOR in Feathersjs applications requires both static code analysis and dynamic runtime testing. The dynamic nature of Feathersjs services means vulnerabilities can hide in unexpected places.

Static analysis should focus on service method implementations. Look for these red flags in your Feathersjs codebase:

// Search for patterns like this:
async get(id, params) {
  return this._super(id, params); // No authorization check
}

async update(id, data, params) {
  return this._super(id, data, params); // No ownership verification
}

async remove(id, params) {
  return this._super(id, params); // No permission validation
}

Pay special attention to services that handle user data, financial information, or sensitive content. Feathersjs applications often have services like 'users', 'accounts', 'messages', 'files', or 'documents' that are prime targets for IDOR attacks.

Dynamic testing with middleBrick specifically targets Feathersjs IDOR vulnerabilities through black-box scanning. The scanner tests unauthenticated and authenticated endpoints for parameter manipulation:

npm install -g middlebrick
middlebrick scan https://your-feathersjs-app.com/api/messages

middleBrick's IDOR detection includes testing for:

  • Sequential ID enumeration (user/1, user/2, user/3...)
  • GUID/UUID substitution attacks
  • Negative ID testing (-1, -999)
  • SQL injection in ID parameters
  • Path traversal in file-based services

For Feathersjs applications using MongoDB, middleBrick tests ObjectId manipulation:

// Test if changing ObjectId grants access to other documents
const validId = new ObjectId('507f1f77bcf86cd799439011');
const maliciousId = new ObjectId('507f1f77bcf86cd799439012');

middleBrick also detects IDOR in Feathersjs's real-time features. Socket.io and Primus-based real-time services can have IDOR vulnerabilities where subscription filters aren't properly enforced:

// Vulnerable real-time subscription
app.service('messages').publish((data, context) => {
  return app.channel(`user-${data.userId}`);
});

// Attacker could subscribe to other users' channels

Feathersjs-Specific Remediation

Feathersjs provides several native mechanisms to prevent IDOR vulnerabilities. The most effective approach combines service-level authorization with proper hook implementation.

The recommended pattern uses Feathersjs's verifyPermissions hook from @feathersjs/authentication-hooks:

const { authenticate } = require('@feathersjs/authentication').hooks;
const { iff, isProvider, verifyPermissions } = require('feathers-hooks-common');

const usersService = {
  before: {
    all: [
      iff(
        isProvider('external'),
        authenticate('jwt')
      )
    ],
    get: [
      verifyPermissions({
        roles: ['admin', 'user'],
        field: 'id',
        owner: async (id, context) => {
          const user = await context.app.service('users').get(id);
          return user.id === context.params.user.id;
        }
      })
    ],
    update: [
      verifyPermissions({
        roles: ['admin'],
        field: 'id',
        owner: async (id, context) => {
          return id === context.params.user.id.toString();
        }
      })
    ]
  }
};

For more granular control, implement custom authorization hooks specific to your business logic:

const checkOwnership = async (context) => {
  const { id, params, method } = context;
  const userId = params.user.id;

  // Special handling for different resource types
  if (context.service.name === 'users') {
    if (method === 'remove' && !params.user.isAdmin) {
      throw new Error('Only admins can delete users');
    }
    if (id !== userId && !params.user.isAdmin) {
      throw new Error('You can only access your own user record');
    }
  }

  if (context.service.name === 'messages') {
    const message = await context.app.service('messages').get(id);
    if (message.userId !== userId && !params.user.isAdmin) {
      throw new Error('Unauthorized access to message');
    }
  }
};

Feathersjs's fastifyAdapter or expressAdapter integration allows middleware-based authorization for REST endpoints:

const isAdmin = (req, res, next) => {
  if (req.user && req.user.isAdmin) {
    return next();
  }
  res.status(403).json({ error: 'Admin privileges required' });
};

app.get('/admin/users/:id', isAdmin, async (req, res) => {
  try {
    const user = await app.service('users').get(req.params.id);
    res.json(user);
  } catch (error) {
    res.status(404).json({ error: 'User not found' });
  }
});

For Feathersjs applications using TypeScript, leverage type safety to prevent IDOR:

interface User {
  id: string;
  email: string;
  isAdmin: boolean;
}

interface Message {
  id: string;
  userId: string;
  content: string;
}

const authorizeMessageAccess = async (id: string, userId: string): Promise => {
  const message = await messagesService.get(id);
  if (message.userId !== userId && !isAdmin(userId)) {
    throw new Error('Unauthorized');
  }
  return message;
};

Finally, implement comprehensive logging and monitoring to detect potential IDOR attacks:

const auditLog = async (context) => {
  const { method, params, id } = context;
  const userId = params.user?.id;
  
  if (userId && method !== 'find') {
    await app.service('audit-logs').create({
      action: `${method} ${context.service.name}`,
      resourceId: id,
      userId: userId,
      timestamp: new Date(),
      ip: params.provider === 'rest' ? params.headers['x-forwarded-for'] : 'socket'
    });
  }
};

Related CWEs: bolaAuthorization

CWE IDNameSeverity
CWE-250Execution with Unnecessary Privileges HIGH
CWE-639Insecure Direct Object Reference CRITICAL
CWE-732Incorrect Permission Assignment HIGH

Frequently Asked Questions

How does middleBrick specifically detect IDOR vulnerabilities in Feathersjs applications?
middleBrick performs black-box scanning that tests Feathersjs endpoints for parameter manipulation vulnerabilities. It systematically modifies ID parameters, tests query parameter injection, and attempts to access resources across different user contexts. The scanner checks for common Feathersjs patterns like sequential ID enumeration, ObjectId manipulation in MongoDB-backed services, and real-time subscription bypasses. middleBrick runs 12 parallel security checks including authentication bypass, BOLA/IDOR, and privilege escalation testing, providing a security risk score with severity levels and remediation guidance.
Can middleBrick scan my Feathersjs API without requiring authentication credentials?
Yes, middleBrick is designed for black-box scanning that doesn't require credentials or configuration. You simply provide the API URL and middleBrick tests the unauthenticated attack surface. For authenticated endpoints, middleBrick can test with simulated authentication if you provide test credentials, but the core scanning works without any setup. This makes it ideal for testing staging environments or public APIs where you don't have access to production credentials.