-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Security: Cross-Company Customer IDOR in CustomerPolicy (CWE-639)
Summary
CustomerPolicy is missing the $user->hasCompany($customer->company_id) check that other resource policies consistently use. This allows users to access, modify, and delete customers belonging to other companies.
Details
Vulnerable: app/Policies/CustomerPolicy.php
All permission methods (view, update, delete, restore, forceDelete) check only Bouncer ability scope:
public function view(User $user, Customer $customer)
{
if (BouncerFacade::can('view-customer', $customer)) {
return true;
}
return false;
}Compare with secure policies:
InvoicePolicy::view():
if (BouncerFacade::can('view-invoice', $invoice) && $user->hasCompany($invoice->company_id)) {
return true;
}Similarly, PaymentMethodPolicy, ReportPolicy, EstimatePolicy, and other resource policies all include $user->hasCompany($resource->company_id).
Bouncer's scope restricts abilities to their assigned scope, but if abilities are assigned at the class level (e.g., view-customer on Customer::class), the scope check passes for ANY customer instance regardless of company.
Impact
A user in Company A can view, edit, and delete customers belonging to Company B by supplying their customer IDs directly.
Suggested Fix
Add $user->hasCompany($customer->company_id) to all per-object permission methods in CustomerPolicy:
public function view(User $user, Customer $customer)
{
if (BouncerFacade::can('view-customer', $customer) && $user->hasCompany($customer->company_id)) {
return true;
}
return false;
}Affected Methods
view()update()delete()restore()forceDelete()
Classification
CWE-639: Authorization Bypass Through User-Controlled Key