Overview
Broken Object Property Level Authorization vulnerabilities occur when an API returns object graphs with sensitive properties without checking the caller's rights. Historically, CVE-1999-0967 described a buffer overflow in the HTML library used by Internet Explorer, Outlook Express, and Windows Explorer via the res: local resource protocol, illustrating how improper handling of untrusted resources can lead to privilege escalation or data corruption. While that CVE targets a different technology stack, it demonstrates the broader risk of mishandling input and resource access. In Node.js/Express, this class of vulnerability manifests when endpoints emit entire entity objects or nested fields to clients without enforcing per-property access control. The risk is that a regular user could receive properties they are not authorized to see, such as private emails, SSNs, internal notes, or admin-only flags.
Code Fix Example
Node.js (Express) API Security Remediation
// Vulnerable pattern (no per-property authorization)
const express = require('express');
const app = express();
// Pretend this is your data store
const db = {
getUserById: async (id) => ({
id,
username: 'user' + id,
email: 'user' + id + '@example.com',
ssn: '123-45-6789',
adminNotes: 'internal data',
})
};
// Simulated middleware that attaches a user to req
app.use((req, res, next) => {
req.user = { id: 1, role: 'user' }; // normal user
next();
});
app.get('/api/users/:id', async (req, res) => {
const user = await db.getUserById(req.params.id);
// Vulnerable: returns entire object including sensitive fields
res.json(user);
});
// Fixed: per-property level authorization (whitelist + role-based access)
app.get('/api/users/:id/fixed', async (req, res) => {
const user = await db.getUserById(req.params.id);
const allowedBase = ['id', 'username'];
const sanitized = {};
allowedBase.forEach((k) => {
if (Object.prototype.hasOwnProperty.call(user, k)) {
sanitized[k] = user[k];
}
});
// Admins get extra fields
if (req.user && req.user.role === 'admin') {
sanitized.email = user.email;
sanitized.ssn = user.ssn;
}
res.json(sanitized);
});
app.listen(3000, () => console.log('Server started'));