PT-2026-80308 · Packagist · Snipe/Snipe-It
Published
2026-08-19
·
Updated
2026-08-19
CVSS v3.1
4.3
Medium
| Vector | AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N |
Impact
Any activated account in a company can read every maintenance record for that company (asset tag, supplier, purchase cost, free-text notes, dates) without holding any asset or maintenance permission.
Summary
MaintenancesController::show() renders a maintenance record without any authorization check. Every other action in the controller authorizes against the asset; show() does not. Any user in the asset's company can read maintenance detail (asset tag, supplier, purchase cost, notes, dates) by visiting /maintenances/{id}, regardless of permissions.Details
php
public function show(Maintenance $maintenance): View|RedirectResponse
{
return view('maintenances.view')->with('maintenance', $maintenance);
}No
authorize() call. The sibling actions all gate on the asset: index() calls authorize('view', Asset::class) (line 33), and edit()/update()/destroy() call authorize('update', $maintenance->asset) (lines 139, 166, 286). The route is registered with only the auth guard:php
Route::resource('maintenances', MaintenancesController::class, ['middleware' => ['auth']]);(
routes/web/hardware.php:185). Route-model binding still applies the company scope, so the read is bounded to the caller's company; the absent permission gate is the defect. Maintenance IDs are sequential and visible in the record URL.Proof of concept
- As an administrator, create an asset in a company (here,
CompanyA). Open the asset, choose Maintenances > Create, and add a record: nameMntA2, supplierSupA, a purchase cost, and notes. The saved record opens at/maintenances/{id}. - As the administrator, create a test user assigned to CompanyA, with every permission left unchecked. Activate the account.
- In a separate browser session, log in as the test user. Confirm it is unprivileged: the Assets and Maintenances navigation items are absent, and browsing to
/hardwarereturns 403. - In the address bar, browse to
http://<host>/maintenances/{id}.
Observed: the maintenance view renders in full for the unprivileged account.
GET /maintenances/5 -> HTTP 200 OK
Renders the "Maintenance" detail page for MntA2:
Asset: AssetA Supplier: SupA Cost: <value> Notes: <text> Dates: <...>
GET /hardware -> HTTP 403 (same account, asset list is gated)
GET /maintenances -> HTTP 403 (same account, maintenance list is gated)
GET /maintenances/2 -> HTTP 302 (record in CompanyB; company scope still hides it)- The
testaccount holds zero permissions and still reads the record. - Only the unguarded
showroute leaks: the list view and the asset pages return 403 for the same account. - A maintenance in a different company (CompanyB) redirects away, confirming the FMCS company scope still holds.
Patches
Fix
Missing Authorization
Found an issue in the description? Have something to add? Feel free to write us 👾
Weakness Enumeration
Related Identifiers
Affected Products
Snipe/Snipe-It