Overview
Broken Object Level Authorization (BOLA) flaws in Laravel apps allow attackers to access resources they should not by changing identifiers in requests. When endpoints return a single model by ID without checking ownership, data can be leaked, and operations like update or delete can be performed on others' resources. In multi-tenant or shared-account systems, this can yield significant data exposure and compliance risk.
In Laravel, BOLA often shows up when controllers fetch models by ID with methods like find($id) or first()/findOrFail($id) and then return the model directly, or when policies are not applied for per-object access. Without per-object checks, authorization decisions rely on global roles or missing gates, which is insufficient for direct object access.
To fix, introduce per-object authorization using Laravel Policies or Gates. Create a policy for the model (e.g., DocumentPolicy) with view/update/delete methods, register it in AuthServiceProvider, and call $this->authorize('view', $document) (or routeModelBinding with authorizeResource). This enforces ownership checks before returning or mutating the resource.
Testing and defense: add tests to ensure unauthorized requests receive 403, lint policies for all single-resource endpoints, and consider scoping queries (e.g., Document::where('id',$id)->where('user_id',auth()->id())) as a defense-in-depth fallback. Review code for similar patterns across controllers.
Code Fix Example
Laravel API Security Remediation
// Vulnerable
class DocumentController extends Controller {
// Vulnerable pattern: fetching by id without ownership check
public function showVulnerable($id) {
$doc = Document::find($id);
return response()->json($doc);
}
// Fixed: enforce per-object authorization via policy/authorize
public function show($id) {
$doc = Document::findOrFail($id);
$this->authorize('view', $doc);
return response()->json($doc);
}
}