Aug 20, 2026·7 min read·58 visits
Chained IDOR and information disclosure in Snipe-IT allows authenticated, low-privileged users to bypass file name randomization and download signed EULAs of any user.
CVE-2026-55694 is a chained Information Disclosure and Insecure Direct Object Reference (IDOR) vulnerability in Snipe-IT prior to version 8.6.3. The vulnerability allows authenticated, restricted users to completely bypass randomized file-naming security controls, leak the obfuscated filenames of signed End User License Agreements (EULAs), and subsequently download these confidential documents across tenant boundaries.
Snipe-IT is an open-source, web-based IT asset and license management platform built on the Laravel framework. The application allows enterprises to track physical hardware, software license allocations, and administrative records. A critical component of this asset tracking workflow is the signature and retention of End User License Agreements (EULAs), which serve as legally binding acceptances of asset transfers.
To protect user confidentiality, the application uses filename obfuscation. When an employee signs a EULA, the resulting PDF is stored on the server using a randomized filename. This security control prevents unauthorized individuals from predicting or brute-forcing the names of stored documents. The primary attack surface resides in the application's REST API and profile management routes, which expose these file handles.
CVE-2026-55694 represents a high-severity vulnerability chain consisting of an information disclosure flaw and an insecure direct object reference (IDOR). This chain allows a low-privileged, authenticated user to completely bypass filename randomization. An attacker can resolve the randomized name of any user's EULA and download the underlying file, undermining tenant and user isolation boundaries.
The core of the vulnerability lies in the incorrect application of authorization checks inside both the API controller layer and the user profile download endpoint. The first flaw occurs in the eulas method of app/Http/Controllers/Api/UsersController.php. When checking permissions, the code invokes $this->authorize('view', User::class). In the Laravel framework, passing a class string instead of an object instance queries class-level privileges. This check determines if the requester has permission to view users in general, rather than validating if they are authorized to access the specific user record mapped to the target identifier.
The second flaw is situated within app/Http/Controllers/ProfileController.php inside the getStoredEula method. The function retrieves the associated database entry from the action_logs table using the requested filename. To verify authorization, the system compares the authenticated user's ID directly with the log entry's target_id using the expression auth()->id() != $logentry->target_id. Because the target_id column is polymorphic, it represents different entities depending on the log type, such as an asset, accessory, or consumable, rather than strictly a user ID.
This polymorphic representation creates an identifier comparison bypass. If a low-privileged user with ID 15 attempts to access a EULA associated with an action log where the target is Asset ID 15, the application evaluates the conditional check as true. Furthermore, the check permits access if the user holds generic class-level permissions to view both users and assets, bypassing organization and company-scoping boundaries.
Below is a flowchart mapping the vulnerable logical execution path:
To understand the precise vulnerability mechanics, we compare the original source code with the corrected version from the official patch repository. The vulnerability in the API layer was corrected by modifying the parameter passed to the authorization function. By changing the class name parameter to a model instance, the application correctly switches from a class-level policy check to an instance-specific validation.
// VULNERABLE - app/Http/Controllers/Api/UsersController.php
public function eulas(User $user, ActionlogsTransformer $transformer)
{
// Evaluates general class view permission only
$this->authorize('view', User::class);
$eulas = $user->eulas;
// ...
}
// PATCHED - app/Http/Controllers/Api/UsersController.php
public function eulas(User $user, ActionlogsTransformer $transformer)
{
// Correctly evaluates specific instance ownership and company scoping
$this->authorize('view', $user);
$eulas = $user->eulas;
// ...
}In the profile file download handler, the custom comparison block was completely removed. The updated logic utilizes Laravel's built-in eager loading to fetch the related user and target objects, and then delegates the authorization logic to the corresponding policy handlers. This prevents null dereferences and secures the file stream against IDOR vectors.
// VULNERABLE - app/Http/Controllers/ProfileController.php
public function getStoredEula($filename)
{
$filename = basename((string) $filename);
$logentry = Actionlog::where('filename', $filename)->first();
// Insecure polymorphic comparison and over-permissive class-level check
$allowed_to_view_users_assets = Gate::allows('view', User::class) && Gate::allows('view', Asset::class);
if (auth()->id() != $logentry->target_id && ! $allowed_to_view_users_assets) {
return redirect()->route('account')->with('error', trans('general.generic_model_not_found', ['model' => 'file']));
}
// ...
}
// PATCHED - app/Http/Controllers/ProfileController.php
public function getStoredEula($filename)
{
$filename = basename((string) $filename);
// Eagerly load relationships to resolve polymorphic target safely
$logentry = Actionlog::where('filename', $filename)->with('user', 'target')->first();
if (! $logentry) {
return redirect()->back()->with('error', trans('general.record_not_found'));
}
// Direct delegation to model instance policy checks
$this->authorize('view', $logentry->target);
$this->authorize('view', $logentry->user);
// ...
}Exploitation of this vulnerability requires network connectivity to an active Snipe-IT web deployment and standard user credentials. The attacker must first authenticate to the application as a standard user. Because the endpoint does not require administrative or asset-manager privileges, the attacker uses their own API bearer token or active session cookie to begin the attack sequence.
First, the attacker identifies a target user's database ID. The database ID is typically a sequentially assigned integer, making discovery trivial through standard enumeration techniques or general system interface inspection. Once the target ID is known, the attacker sends an authenticated GET request to the vulnerable endpoint at /api/v1/users/{target_id}/eulas. The server responds with JSON metadata representing the target's signed EULAs, which exposes the specific, randomized filename.
Second, the attacker requests the exposed filename using the vulnerable /account/stored-eula-file/{filename} route. If the attacker's own user ID matches the polymorphic target_id of the underlying action log (e.g., matching a log entry for an unrelated asset assignment), or if they possess general view permissions for users and assets, the server bypasses the access restrictions. The application retrieves the PDF file from storage and returns a 200 OK HTTP status alongside the binary payload.
The security impact of CVE-2026-55694 is highly significant for organizations that process sensitive agreements. Signed EULAs are legal instruments. They commonly contain the employee's full name, internal username, system email address, asset configurations, specific serial numbers, and physical or digital signatures. Unauthorized exposure of these elements compromises employee privacy and provides an attacker with reconnaissance data for subsequent social engineering attacks.
From an architecture perspective, this vulnerability represents a complete bypass of multi-tenant boundaries. In setups utilizing Snipe-IT's Full Multiple Companies Support (FMCS), different organizations share the same database instance but are strictly segmented. Because the vulnerable profile controller relied on class-level and polymorphic ID matching, the boundary is ignored. An attacker in Company A can read the signed agreements of users belonging to Company B, exposing proprietary enterprise data.
The CVSS v4.0 base score is rated at 7.1 (High) with the vector CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N. This calculation reflects a network-based attack vector with low complexity, requiring low privileges, with high confidentiality impact on the core system, and zero impact on integrity or availability. The vulnerability represents a severe threat to data classification controls.
The definitive solution is to upgrade the Snipe-IT installation to version 8.6.3 or later. This release updates the code logic to enforce instance-level authorization and eliminates the polymorphic target identifier mismatch. The update is applied by checking out the tag v8.6.3 from the git repository and running dependency updates.
If immediate software upgrades are not possible, administrators must implement network-level controls to block the vulnerable routes. Using a reverse proxy, such as Nginx or Apache, administrators can intercept incoming traffic and reject requests containing the specific URI paths. While this restricts normal users from viewing their own signed files via these endpoints, it prevents unauthorized exposure until a formal patch can be deployed.
An inspection of the remediated code confirms that the fix is comprehensive. By migrating the logic to Laravel's native policies, the application ensures that all company-scoping boundaries and asset verification steps are consistently applied. Security teams should audit their database logs for any anomalous requests directed towards the /api/v1/users EULA paths to identify potential exploitation attempts.
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Snipe-IT Grokability | < 8.6.3 | 8.6.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-639 |
| Attack Vector | Network (AV:N) |
| CVSS v4.0 Score | 7.1 (High) |
| Exploit Status | None |
| KEV Status | Not Listed |
| Ransomware Association | No |
| Vulnerability Class | Information Disclosure & IDOR Chain |
The system fails to prevent a user from accessing resources by altering a key, such as an ID, that determines which resource is retrieved.
CVE-2026-109619 (PHP2Shell) is a critical Use-After-Free vulnerability in the core PHP engine caused by improper global state cleanup during out-of-memory exception handling across persistent worker requests.
In Python virtualenv prior to version 21.14.9, activation script generators and configuration writers use Path.exists() before writing files. Because Path.exists() resolves symbolic links, it returns False for dangling symlinks. Consequently, virtualenv skips unlinking pre-planted symbolic links or hard links, writing data directly to target locations outside the intended virtual environment directory.
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.
An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.
ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.
CVE-2026-70035 is a high-severity Remote Code Execution (RCE) vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio caused by improper handling during the deserialization of untrusted data (CWE-502). An unauthenticated attacker can execute arbitrary code within the context of the affected process by delivering a crafted serialized payload.