Broken Object Property Level Authorization

Broken Object Property Level Authorization Node.js (Express) [GHSA-2jf5-6wwv-vhxx]

[Updated May 2026] Updated GHSA-2jf5-6wwv-vhxx

Overview

Broken Object Property Level Authorization vulnerabilities enable attackers to access or modify data they should not be allowed to see by simply supplying an object ID or key in API requests. Real-world impacts include exposure of personal data, financial details, or other sensitive resources, which can lead to regulatory penalties, brand damage, and loss of user trust. Attackers can iteratively enumerate IDs to harvest information across accounts, and in multi-tenant apps this can escalate privileges from one user to another, undermining the confidentiality guarantees of the system. In Node.js with Express, this class of vulnerability often manifests when endpoints fetch resources by an identifier (for example, /api/orders/:orderId or /api/users/:id) and return the result without validating that the current user owns or is authorized to access that object. If authentication exists but authorization is implemented poorly or at the client side only, attackers can access or alter data belonging to others. The result can be data leaks, tampering, or denial of service for affected resources. Remediating these issues requires explicit, server-side authorization checks at the API boundary. After loading a resource, compare its owner or required permissions to the authenticated user (or enforce ownership in the database query). Prefer implementing ABAC/RBAC patterns and centralizing authorization logic in middleware or route guards. Combine with proper error handling (do not reveal sensitive details) and thorough testing to simulate unauthorized access attempts across endpoints.

Code Fix Example

Node.js (Express) API Security Remediation
/* Vulnerable vs Fixed: Node.js (Express) example demonstrating side-by-side patterns */
const express = require('express');
const app = express();

// In-memory mock data for demonstration
const orders = [
  { id: '1', customerId: 'u1', item: 'Widget' },
  { id: '2', customerId: 'u2', item: 'Gadget' }
];

// Simple mock authentication middleware
function mockAuth(req, res, next) {
  // In a real app, replace with proper authentication (JWT, sessions, etc.)
  req.user = { id: 'u1', isAdmin: false };
  next();
}
app.use(mockAuth);

// Vulnerable pattern: no authorization check after retrieving by ID
app.get('/api/orders/:orderId', (req, res) => {
  const order = orders.find(o => o.id === req.params.orderId);
  if (!order) return res.status(404).send();
  // No ownership/permission check; returns data regardless of who requests it
  res.json(order);
});

// Fixed pattern: enforce ownership/role-based access control
app.get('/api/orders/:orderId/secure', (req, res) => {
  const order = orders.find(o => o.id === req.params.orderId);
  if (!order) return res.status(404).send();
  const user = req.user;
  if (!user) return res.status(401).send({ error: 'Unauthorized' });
  // Check ownership or admin role
  if (order.customerId !== user.id && !user.isAdmin) {
    return res.status(403).send({ error: 'Forbidden' });
  }
  res.json(order);
});

app.listen(3000, () => console.log('Server running on port 3000'));

CVE References

Choose which optional cookies to allow. You can change this any time.