Broken Object Property Level Authorization

Broken Object Property Level Authorization Node.js (Express) [CVE-1999-1016]

[Updated Mar 2026] Updated CVE-1999-1016

Overview

Broken Object Property Level Authorization vulnerabilities expose a class of access-control failures where an attacker can manipulate object properties in requests to access or modify data they should not own. The real-world impact is seen in historic DoS scenarios like CVE-1999-1016, where remote web content could trigger denial of service via oversized HTML form fields, exhausting CPU resources. While CVE-1999-1016 targets legacy UI components, the core lesson remains: untrusted input can steer server behavior in harmful ways. In modern Node.js (Express) environments, attackers may attempt to set or modify ownership or permission-related properties in the request body, leading to unauthorized data access or privilege escalation if the server trusts client-supplied fields and bypasses proper authorization checks. This guide ties that historical DoS insight to the contemporary risk of object-property level authorization in Node.js/Express apps and shows concrete remediation patterns.

Code Fix Example

Node.js (Express) API Security Remediation
const express = require('express');
const app = express();
app.use(express.json());

// In-memory data for demonstration
let items = [
  { id: 'item1', ownerId: 'user1', data: 'secret1' },
  { id: 'item2', ownerId: 'user2', data: 'secret2' }
];

// Mock authentication middleware (for demonstration only)
function mockAuth(req, res, next) {
  // In real apps, extract user from a session or JWT
  req.user = { id: 'user1', role: 'user' };
  next();
}
app.use(mockAuth);

// Vulnerable pattern: merges req.body directly, allowing property manipulation (e.g., ownerId)
app.patch('/items/:id', (req, res) => {
  const item = items.find(i => i.id === req.params.id);
  if (!item) return res.status(404).send('Not found');
  // Vulnerable: client can set/override sensitive fields like ownerId
  const updated = { ...item, ...req.body };
  items = items.map(i => (i.id === item.id ? updated : i));
  res.json(updated);
});

// Fixed pattern: validate and whitelist fields; enforce authorization on ownership
app.patch('/items/:id/fixed', (req, res) => {
  const item = items.find(i => i.id === req.params.id);
  if (!item) return res.status(404).send('Not found');
  // Enforce authorization: only owner or admin can update
  if (req.user.id !== item.ownerId && req.user.role !== 'admin') {
    return res.status(403).send('Forbidden');
  }
  // Whitelist allowed fields to update
  const allowed = ['data'];
  const payload = {};
  for (const key of allowed) {
    if (Object.prototype.hasOwnProperty.call(req.body, key)) {
      payload[key] = req.body[key];
    }
  }
  const updated = { ...item, ...payload };
  items = items.map(i => (i.id === item.id ? updated : i));
  res.json(updated);
});

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

CVE References

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