CVE-2026-55516 Overview
CVE-2026-55516 is a broken access control vulnerability in Snipe-IT, an open-source IT asset and license management system. The flaw affects the maintenance record update endpoint prior to version 8.6.2. When processing PATCH or PUT requests to /api/v1/maintenances/{maintenance_id}, the application verifies access to the existing maintenance record and asset but fails to re-authorize the newly supplied asset_id. An authorized user can move a maintenance record onto an asset that exists outside their company scope, breaking multi-tenant isolation boundaries.
Critical Impact
Authenticated users can re-parent maintenance records onto assets belonging to other companies, violating tenant isolation and enabling cross-company data integrity attacks.
Affected Products
- Snipe-IT versions prior to 8.6.2
- Snipe-IT API endpoint /api/v1/maintenances/{maintenance_id}
- Multi-company Snipe-IT deployments with company-scoped access controls
Discovery Timeline
- 2026-07-10 - CVE-2026-55516 published to NVD
- 2026-07-14 - Last updated in NVD database
Technical Details for CVE-2026-55516
Vulnerability Analysis
The vulnerability is classified as [CWE-639]: Authorization Bypass Through User-Controlled Key. Snipe-IT supports a multi-company mode where assets and related records are scoped to a specific company. The MaintenancesController update method validated whether the current user could access the maintenance record's existing asset. It then applied attacker-controlled input, including a new asset_id, without repeating the authorization check against the target asset.
An authenticated user with permission to edit at least one maintenance record can submit an asset_id referencing an asset in a different company. The record is re-parented server-side, corrupting maintenance history and enabling manipulation of records tied to assets the user cannot otherwise access.
Root Cause
The root cause is a missing authorization check on the newly supplied key. The controller relied solely on Company::isCurrentUserHasAccess($maintenance->asset) against the original asset. The mass-assigned asset_id field bypassed that check because no equivalent validation ran against the new target asset before saving.
Attack Vector
Exploitation requires network access to the Snipe-IT API and a valid authenticated session with low privileges. The attacker sends a PATCH or PUT request to /api/v1/maintenances/{maintenance_id} containing an asset_id pointing to an out-of-scope asset. No user interaction is required.
// Patch applied in app/Http/Controllers/Api/MaintenancesController.php
if ($maintenance = Maintenance::with('asset')->find($id)) {
// The asset this maintenance is attached to is not valid or has been deleted
if (! $maintenance->asset) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.item_not_found', ['item_type' => trans('general.asset'), 'id' => $id])));
}
// Can this user manage the existing asset?
if (! Company::isCurrentUserHasAccess($maintenance->asset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.action_permission_denied', ['item_type' => trans('admin/maintenances/general.maintenance'), 'id' => $id, 'action' => trans('general.edit')])));
}
// If the request changes asset_id, verify the new asset is accessible
if ($request->filled('asset_id') && (int) $request->input('asset_id') !== $maintenance->asset_id) {
$newAsset = Asset::find($request->input('asset_id'));
if (! $newAsset) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.item_not_found', ['item_type' => trans('general.asset'), 'id' => $request->input('asset_id')])));
}
if (! Company::isCurrentUserHasAccess($newAsset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.action_permission_denied', ['item_type' => trans('general.asset'), 'id' => $request->input('asset_id'), 'action' => trans('general.edit')])), 403);
}
}
}
Source: GitHub Commit 905d498
Detection Methods for CVE-2026-55516
Indicators of Compromise
- PATCH or PUT requests to /api/v1/maintenances/{id} containing an asset_id value that differs from the maintenance record's original asset.
- Maintenance records whose asset_id references assets outside the requesting user's company scope in audit logs.
- API activity from low-privileged accounts modifying maintenance records at unusual rates.
Detection Strategies
- Review Snipe-IT application logs and web server access logs for PATCH/PUT calls to the /api/v1/maintenances/ path.
- Correlate maintenance record updates against the requesting user's company_id and the target asset's company_id to identify cross-tenant modifications.
- Deploy a Web Application Firewall (WAF) rule to inspect API request bodies for asset_id changes and alert on anomalies.
Monitoring Recommendations
- Enable API request body logging for the maintenances endpoint to preserve forensic evidence.
- Monitor for authentication tokens issued to low-privilege users that suddenly modify records across multiple company scopes.
- Alert on HTTP 200 responses to maintenance update requests where the asset_id field is included in the payload.
How to Mitigate CVE-2026-55516
Immediate Actions Required
- Upgrade Snipe-IT to version 8.6.2 or later immediately.
- Audit existing maintenance records to identify entries where the asset's company_id does not align with historical ownership.
- Rotate API tokens for accounts observed sending suspicious maintenance update requests.
Patch Information
The fix is included in Snipe-IT version 8.6.2 via commit 905d498ecdb0ee5591231c97bf48435e92044368. The patch adds an explicit Company::isCurrentUserHasAccess() check against the new asset when asset_id differs from the current value. Full details are available in the GitHub Security Advisory GHSA-575r-357h-fhch and the GitHub Release v8.6.2 notes.
Workarounds
- Restrict API access to trusted administrators until the upgrade is complete.
- Temporarily disable API tokens for non-administrative users via the Snipe-IT admin console.
- Place the Snipe-IT API behind a reverse proxy that blocks PATCH/PUT requests containing an asset_id field on the maintenances endpoint.
# Example nginx rule to block asset_id modifications on maintenance updates
location ~ ^/api/v1/maintenances/[0-9]+$ {
if ($request_method ~ ^(PATCH|PUT)$) {
set $block_flag "A";
}
if ($request_body ~* "asset_id") {
set $block_flag "${block_flag}B";
}
if ($block_flag = "AB") {
return 403;
}
proxy_pass http://snipeit_backend;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

