Bola Idor in Laravel
How Bola Idor Manifests in Laravel
Bola Idor (Broken Object Level Authorization) in Laravel applications often stems from the framework's implicit route model binding and Eloquent ORM patterns. When developers rely on Laravel's automatic model resolution without proper authorization checks, attackers can manipulate IDs in URLs to access other users' data.
The most common pattern involves Laravel's route model binding:
// Vulnerable controller method
public function show(User $user) {
return response()->json($user);
}
When a request hits /api/users/1, Laravel automatically queries for User ID 1 and injects it into the method. An attacker simply changes the ID to access other users' records without any authorization verification.
Another Laravel-specific manifestation occurs with Eloquent relationships:
// Vulnerable - no authorization check
public function index(Post $post) {
return response()->json($post->comments);
}
Even though the Post model is resolved, the comments relationship returns all comments regardless of whether the authenticated user owns the post or has permission to view these comments.
API resources compound this issue:
// Vulnerable API Resource
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'posts' => PostResource::collection($this->whenLoaded('posts')),
];
}
}
The resource exposes all user data without checking if the requesting user should see this information.
Mass assignment vulnerabilities in Laravel can also lead to Bola Idor:
// Vulnerable - no authorization before update
public function update(Request $request, User $user) {
$user->update($request->all());
return response()->json($user);
}
An authenticated user could modify any user's record by changing the ID in the URL, updating fields they shouldn't have access to modify.
Laravel-Specific Detection
Detecting Bola Idor in Laravel requires examining both the code structure and runtime behavior. In code review, look for these Laravel-specific patterns:
// Patterns to flag
// 1. Route model binding without authorization
public function show(User $user) { ... }
// 2. Relationship access without ownership checks
public function index(Post $post) {
return $post->comments;
}
// 3. Resource controllers missing policies
public function destroy(User $user) { ... }
middleBrick's Laravel-specific scanning analyzes these patterns automatically. The scanner tests unauthenticated endpoints by manipulating IDs and relationship parameters to detect unauthorized data exposure.
For runtime detection, middleBrick's black-box scanning tests the actual API behavior:
# middleBrick CLI scan output example
$ middlebrick scan https://api.example.com
Vulnerability: Bola Idor - User Data Exposure
Severity: HIGH
Endpoint: GET /api/users/{user}
Issue: No authorization check on route model binding
Remediation: Add policy check or ownership verification
Vulnerability: Bola Idor - Comment Data Leakage
Severity: MEDIUM
Endpoint: GET /api/posts/{post}/comments
Issue: Comments returned without post ownership verification
Remediation: Verify authenticated user owns the post
The scanner's 12 security checks include specific Bola Idor detection that tests ID manipulation across all endpoints, looking for data leakage patterns unique to Laravel's conventions.
Manual testing involves systematically changing ID parameters in authenticated sessions:
# Test pattern
GET /api/users/1
GET /api/users/2
GET /api/posts/1/comments
GET /api/posts/2/comments
If the responses contain different users' data without proper authorization errors, Bola Idor exists.
Laravel-Specific Remediation
Laravel provides several native mechanisms to fix Bola Idor vulnerabilities. The most robust approach uses Laravel Policies:
// Generate policy
php artisan make:policy UserPolicy --model=User
// UserPolicy.php
public function view(User $currentUser, User $user)
{
return $currentUser->id === $user->id;
}
public function update(User $currentUser, User $user)
{
return $currentUser->id === $user->id;
}
// Register in AuthServiceProvider
protected $policies = [
User::class => UserPolicy::class,
];
// Controller with policy authorization
public function show(User $user)
{
$this->authorize('view', $user);
return response()->json($user);
}
For relationship-based endpoints, add ownership verification:
// Secure controller method
public function index(Post $post)
{
$this->authorize('view', $post);
if ($post->user_id !== auth()->id()) {
return response()->json([
'error' => 'Unauthorized'
], 403);
}
return response()->json($post->comments);
}
Laravel's Form Request validation can centralize authorization:
// Generate request
php artisan make:request UpdateUserRequest
// UpdateUserRequest.php
public function authorize()
{
return $this->user()->id === $this->route('user')->id;
}
// Controller
public function update(UpdateUserRequest $request, User $user)
{
$user->update($request->validated());
return response()->json($user);
}
For API resources, add conditional loading:
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->when($this->id === $request->user()->id, $this->email),
'posts' => PostResource::collection(
$this->whenLoaded('posts', function () use ($request) {
return $this->posts()->where('user_id', $request->user()->id)->get();
})
),
];
}
}
middleBrick's continuous monitoring in Pro tier helps verify these fixes by regularly scanning your API endpoints and alerting if new Bola Idor vulnerabilities are introduced during development.
Related CWEs: bolaAuthorization
| CWE ID | Name | Severity |
|---|---|---|
| CWE-250 | Execution with Unnecessary Privileges | HIGH |
| CWE-639 | Insecure Direct Object Reference | CRITICAL |
| CWE-732 | Incorrect Permission Assignment | HIGH |