Open actionable advisories and recorded vendor fixes. This public package view has no inventory attached and cannot establish whether your deployment is affected. A vendor fix never resolves your finding; verify your installed version and the source guidance.
Open advisories
74 actionable advisories, newest first. Withdrawn advisories and news are excluded. Coverage is partial.
Snipe-IT's uploaded-files API accepts XML documents and later serves them inline without applying the safe-inline allowlist used by the equivalent web controller. An authenticated user who can attach files to a supported object can upload an XSLT stylesheet and an XML document that references it through xml-stylesheet. When another authorized user opens the XML file through the API with ?inline=true, the browser applies the attacker-controlled stylesheet, which produces HTML containing JavaScript in the Snipe-IT origin. This was reproduced against commit df8e3b144331d0c1cc14778f900e7646d1d9a509 (v8.6.3-231-gdf8e3b1443). The attack requires an authenticated account with file access to at least one supported object and one victim interaction. Scope changes because attacker-controlled code executes in another user's Snipe-IT security context. The script can read same-origin data available to the victim and perform authenticated actions as that victim. Affected Components -…
Recommended action: Upgrade to 8.7.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact A user with the "customfields.create" permission can store HTML/JS in a Custom Field name, which is later rendered as an asset-list column title WITHOUT escaping at app/Presenters/AssetPresenter.php line 364 ('title' = $field-name) and injected into the table header by the bundled bootstrap-table plugin. It executes for anyone who opens an asset list (e.g. /hardware), including superusers, on page load with no interaction. Since "customfields.create" can be granted to non-superusers, a lower-privileged user gets script execution in a superuser's session - privilege escalation. STEPS TO REPRODUCE 1. As a user with "customfields.create", create a Custom Field named: <img src=x onerror=alert(1) 2. Add the field to a fieldset that is associated with an asset model. 3. Open /hardware - the payload executes on load. DEMONSTRATED IMPACT An account holding ONLY "customfields.create" (HTTP 403 on /users) planted a payload that, when a superuser opened /hardware, issued an authenticated…
Recommended action: Upgrade to 8.7.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact An attacker who knows a victim's password fully bypasses that account's 2FA and obtains a persistent token with full API access as the user (read and write across the user's permissions, including admin if the victim is an admin). The token is an API credential, not a web/UI session (using it on web routes redirects to /login), but the REST API covers essentially the whole application. If the victim is an admin, the token can also call the admin users/twofactorreset endpoint, which is in the same un-gated API surface, to clear the account's enrolled 2FA. The next login is then forced to re-enroll a second factor, which the password-holding attacker can complete with their own device, taking over the account's web access and locking the legitimate user out. Summary: 2FA is enforced only by the web middleware group, not the api group, and the personal-access-token endpoint is in the api group. A session that has passed the password check but not the 2FA can mint a persistent API…
Recommended action: Upgrade to 8.7.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact The update() method in UsersController passes the permission request field unconditionally to NormalizePermissionsPayloadAction, which returns an empty array when the field is absent. The result is passed to PreserveUnauthorizedPrivilegedPermissionsAction, which selectively restores only the superuser key (when the editor is not a superuser) and the admin key (when the editor is neither admin nor superuser). All other permissions — including the admin flag itself when the editing user is an admin — are discarded and $user-permissions is overwritten with the sparse result. The canEditAuthFields gate permits admins to update other non-superuser accounts (including other admins). When an admin sends a PUT /users/{id} request for another admin without including the permission field, the target's admin flag and all granular permissions are permanently destroyed. The target loses administrative access entirely with no error, warning, or out-of-band notification. A secondary,…
Recommended action: Upgrade to 8.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact The API endpoint for updating asset maintenance records allows an authorized user to change the assetid of an existing maintenance record to an asset outside their company scope. In a Full Multiple Company Support / multi-company deployment, this allows a user from Company A to attach or move a maintenance record onto an asset belonging to Company B. The endpoint appears to authorize access to the existing maintenance record’s asset, but does not re-authorize the newly supplied assetid before saving the update. Affected endpoint PATCH /api/v1/maintenances/{maintenanceid} Also likely affected: PUT /api/v1/maintenances/{maintenanceid} Preconditions The attacker needs: - A valid authenticated API token. - Permission to update asset maintenance records. - Access to a maintenance record currently attached to an asset in their own company. The attacker does not need access to the target asset’s company. Root cause In the API maintenance update flow, the application checks access to…
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact A user with the reports.view permission can delete pending checkout acceptance records by global ID, even when the acceptance belongs to an asset in another company. The report listing page appears to scope visible unaccepted assets, but the delete endpoint directly looks up CheckoutAcceptance::pending()-find($acceptanceId) and deletes it without checking whether the current user has access to the related checkoutable asset. Preconditions The attacker needs: - A valid authenticated web session. - reports.view permission. - Knowledge or guessability of a pending checkoutacceptances.id. The attacker does not need access to the asset/company associated with the target acceptance. Root cause The delete action authorizes only report access, then deletes a pending acceptance by global ID: The code does not check whether the current user can access the acceptance’s related checkoutable asset/accessory/license/etc. In multi-company mode, this allows a reports user from one company to…
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact Because default.blade.php is the base layout loaded on every authenticated page, all active user sessions are affected immediately upon the next page load after the payload is saved. An attacker who has compromised an admin account (or who is a malicious insider) can use this to silently exfiltrate session tokens from all other users, including other administrators. Additionally, the Content Security Policy is disabled by default in Snipe-IT installations, which removes the primary browser-level mitigation for this class of attack. Details The headercolor setting (and related color settings such as navcolor and linkcolor) is rendered inside a CSS <style block using Laravel's {{ }} syntax: Although {{ }} applies HTML entity encoding, this is insufficient in a CSS context. An attacker with superadmin access to the Settings Branding page can inject arbitrary CSS by setting the headercolor value to something like: This breaks out of the CSS property value and injects a new rule…
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact The legacy single-seat license checkin flow authorizes the action with the checkout permission instead of the checkin permission. Because of this, a user who is allowed to assign licenses but not unassign them can still directly access the old checkin endpoint and reclaim a license seat that is currently assigned to another user or asset.
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact The API endpoint for adding a license to a predefined kit (POST /api/v1/kits/{kitid}/licenses) only checks whether the caller can edit kits, but does not perform object-level authorization on the referenced license itself. Because of this, a low-privilege user with only predefined-kit permissions can still bind a license that they should not be allowed to access or manage into a kit.
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact The route POST /account/request/{itemType}/{itemId}/{cancelbyadmin?}/{requestingUser?} accepts cancelbyadmin as a plain URL path segment with no authorization check. Any authenticated user regardless of permissions can set this parameter to a truthy value and supply a victim's user ID to silently cancel that user's pending asset requests. The attacker only needs an active session; no elevated privilege is required. Patches Patched in 8.6.1
Recommended action: Upgrade to 8.6.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact The createdby of an import file can be arbitrarily overwritten via the Importer API endpoint by a user with CSV import capabilities who also has a valid API key.
Recommended action: Upgrade to 8.6.1 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact The displaySig action in ActionlogController serves signature image files from a private upload directory. The filename parameter from the HTTP route is concatenated directly into a filesystem path with no sanitization, allowing an authenticated attacker to traverse outside the intended directory and read arbitrary files accessible to the web server process. Reported by https://github.com/securin-public
Recommended action: Upgrade to 8.5.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact When Full Multiple Companies Support and scopelocationsfmcs are both enabled, the API endpoint for creating locations can still create a child location under a parent location from a different company. The code detects the invalid parent/child company mismatch, but it appears not to return immediately, so the request continues and the record is still saved. The equivalent Web flow correctly rejects the same relationship. This breaks the expected company-boundary enforcement for location hierarchies under FMCS. It allows cross-company parent/child relationships to be inserted into the location tree, which can affect hierarchy integrity, downstream business logic, and the consistency of company isolation between the Web and API interfaces. Patches Patched in https://github.com/grokability/snipe-it/commit/9a8cbd6e00613a726b639a97a1da71b3c54f9489
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact An authenticated user holding the import and assets.update permissions can delete arbitrary files on the server filesystem by injecting a path traversal string into an asset's image field via CSV import, then triggering the image deletion feature.
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact A low-privilege user can store an active-content payload as an asset attachment and have it served inline, same-origin, with an active Content-Type, achieving stored XSS. The application sanitizes uploads only when PHP finfo detects image/svg+xml. By submitting an XHTML document whose finfo MIME is text/xml (an allowed extension), the svg-sanitize branch is skipped, the <script is stored raw, and the inline-serve path returns it as text/xml; charset=utf-8 with Content-Disposition: inline — which the browser renders as a live XHTML document and executes. The dedicated StorageHelper::allowSafeInline() whitelist that should have constrained inline-renderable types is never wired into the serve path. Details Vulnerable code — sanitizer keyed on finfo MIME app/Http/Requests/UploadFileRequest.php:46-53 Vulnerable code — inline serve, no allowSafeInline() app/Http/Controllers/UploadedFilesController.php:103 StorageHelper::allowSafeInline() (app/Helpers/StorageHelper.php:88) exists to…
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact CommonMark is configured with htmlinput = 'escape', which blocks raw HTML injection. However, javascript: URIs in Markdown hyperlinks are not sanitized. A user with assets.edit permission can inject a malicious link into any markdown-textarea custom field. Any user who opens the asset detail page and clicks the link executes arbitrary JavaScript in their browser session.
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact An authenticated user with only users.view can open another user's detail page and see assigned license, accessory, and consumable data even though the same account is denied direct access to the Licenses, Accessories, and Consumables modules. The leaked data includes software license names, purchase order/order values, accessory and consumable names, assignment notes, and purchase costs. Attacker Model Authenticated user with only: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ json {"users.view":"1"} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The attacker does not have: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ json { "licenses.view": "1", "accessories.view": "1", "consumables.view": "1", "assets.view": "1" } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Affected Component - app/Http/Controllers/Users/UsersController.php -…
Recommended action: Upgrade to 8.6.1 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact The user edit flow stores url()-previous() into Laravel's intended URL session value and later redirects with redirect()-intended(...) when redirectoption=back is submitted. Because the previous URL is derived from the attacker-controlled Referer header, an authenticated user performing a normal user-edit action can be redirected to an external attacker-controlled site. An attacker who can cause a logged-in user with permission to edit a user record to open the edit page with an attacker-controlled Referer value. The application can be used as a trusted redirector after a legitimate user edit action. This can support phishing or trust-boundary attacks against Snipe-IT users and matches a historical open redirect class where session-stored navigation context influences redirect destinations. Patches Patched in f4cac96358
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact An authenticated non-admin user with users.view and users.edit, but without users.delete, can directly POST to /users/bulksave and soft-delete another non-admin user. The UI and confirmation route require users.delete, but the destructive sink only authorizes update. Attacker Model Authenticated non-admin user with: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ json {"users.view":"1","users.edit":"1"} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The attacker does not have users.delete, admin, or superuser. Affected Component - routes/web/users.php - app/Http/Controllers/Users/BulkUsersController.php - Endpoint: POST /users/bulksave Root Cause The UI only exposes bulk delete to users with delete permission: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ php @can('delete', \App\Models\User::class) <option value="delete"...</option <option value="merge"...</option @endcan…
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact In Snipe-IT v8.6.1 and lower, Actionlog::logaction() stores the request User-Agent header in useragent. That value is later included in the Activity Report CSV export by ReportsController::postActivityReport() and written with plain fputcsv(). A low-privileged authenticated user can set a formula-like User-Agent, perform a logged action, and have that value stored in the activity log. If an admin or report viewer later exports the Activity Report and opens it in spreadsheet software, the formula may execute. Example payload: User-Agent: =HYPERLINK("https://example.com/","click")
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact The table component derives data-selected-count-id from the component $name value. On manufacturer and supplier detail pages, stored manufacturer or supplier names are passed into affected table components as that name value. The client-side JavaScript later reads the browser-decoded data-selected-count-id, uses it as a selector, and concatenates countId.substring(1) directly into an HTML string passed to jQuery .after(). Affected commit: b224cc636c6780386e3f73f03d1171f52ab4c37a Example payload for a manufacturer or supplier name: x[foo="<svg/onload=alert(1)"] The issue appears to involve the following flow: Stored supplier/manufacturer name - table component data-selected-count-id - browser decodes the attribute - JavaScript reads countId - countId is used as a selector - countId.substring(1) is concatenated into HTML - jQuery .after() inserts attacker-controlled markup - JavaScript executes in the victim's browser Potential impact includes arbitrary JavaScript execution in…
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
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 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: (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…
Recommended action: Upgrade to 8.6.3 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact An attacker can completely bypass file-name randomization security and without authorization download confidential, signed EULA files belonging to any other user across the application. Steps to Reproduce: 1. Log in as a restricted user. 2. Send a GET request to /api/v1/users/{targetid}/eulas (where targetid belongs to a restricted/denied user). 3. Observe the response leaks the secret EULA filename (e.g., eula-xxx.pdf). 4. Attempt to access this file via the main route: GET /stored-eula-file/{filename} (This will correctly return 403 Forbidden). 5. Now, access the file via the vulnerable profile route: GET /account/stored-eula-file/{filename}. 6. Observe that the server returns a 200 OK and successfully downloads the target user's secret EULA file. Patches Fixed in https://github.com/grokability/snipe-it/commit/f15d78621b003be30ac114ba68626683894935ef
Recommended action: Upgrade to 8.6.3 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact Due to inconsistent authorization checks, a company-scoped user can bypass tenant boundaries to read, mutate, and soft-delete users who do not belong to any company (companyid = null). While direct instance authorization (isCurrentUserHasAccess) correctly denies access to these out-of-scope users, multiple API endpoints and bulk action web routes fail to enforce this restriction, relying instead on class-level permissions or broad scoped queries. Impact: A malicious user scoped to a specific company (e.g., Company A) can: Data Leakage: Extract PII and assigned licenses of users outside their tenant via the API (/api/v1/users and /api/v1/users/{id}/licenses). Data Modification: Mutate out-of-scope user profiles (e.g., changing city, notes) via the /users/bulkeditsave web route. Data Deletion & Asset Theft: Soft-delete out-of-scope users and transfer their assigned assets to themselves via the /users/merge web route. Patches Patched in…
Recommended action: Upgrade to 8.6.3 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.
Impact A cross-tenant data injection vulnerability was identified in the Snipe-IT Accessories API when Full Multiple Companies Support (FMCS) is enabled. A low-privileged authenticated user belonging to one company can create an accessory record under another company by supplying a foreign companyid value in the API request body. The issue occurs because the API create path mass-assigns request parameters directly to the Accessory model, and the Accessory model allows companyid to be mass assigned. Unlike the web controller, which uses Company::getIdForCurrentUser() to enforce the authenticated user’s company context, the API controller does not apply equivalent tenant enforcement during accessory creation. As a result, a Company A user can inject persistent accessory records into Company B. The injected records are then visible to Company B users as legitimate Company B inventory records. This breaks the integrity of company-scoped inventory data and represents a tenant isolation…
Recommended action: Upgrade to 8.6.2 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.