Overview
Broken Object Property Level Authorization (BOPLA) vulnerabilities in API servers allow an attacker to access or modify resources they should not see, simply by choosing a different object identifier and relying on insufficient checks. In real-world apps this can expose sensitive user data, documents, orders, or configuration objects across tenants. Even when authentication succeeds, authorization decisions must enforce ownership and permissions for every object in scope.
In Hapi-based services, endpoints frequently fetch resources by an id drawn from request.params, request.query, or request.payload and return the object directly without validating that the current user owns or is permitted to access it. If the code uses a parameter to index into a collection (for example documents.findById(id)) and does not compare doc.ownerId to request.auth.credentials.userId, an attacker can retrieve or alter another user's data.
The real-world impact includes data leakage, privacy violations, regulatory risk, and potential business loss. Attackers could read, update, or delete sensitive records, and your logs could reveal internal user IDs. This vulnerability often stems from missing centralized authorization and fragmented checks in route handlers.
Remediation pattern: implement strict ownership checks in a centralized layer; verify resource ownership before any response; use Hapi pre-handlers or route guards with a clear policy; limit what is returned; add tests that simulate unauthorized access; log and monitor failed authorization attempts and monitor for anomalous access patterns.
Code Fix Example
Hapi API Security Remediation
Vulnerable:
const handlerV = async (request, h) => {
const id = request.params.id;
const doc = await db.documents.findById(id);
return doc; // no authorization check
};
Fixed:
const handlerF = async (request, h) => {
const id = request.params.id;
const doc = await db.documents.findById(id);
if (!doc || doc.ownerId !== request.auth.credentials.userId) {
throw Boom.forbidden('Not authorized');
}
return doc;
};