CVE-2026-86749 in Snipe-IT
Summary
by MITRE • 09/09/2026
Snipe-IT versions <= 8.6.3 (fixed in 8.7.0) do not check the return value of storage write operations in ImageUploadRequest::handleImages(). Because Laravel's default disk mode does not throw on failure, a silently failed Storage::disk('public')->put(...) call still caused the application to delete the previous image via deleteExistingImage() and to reassign and persist the model's image reference to the new filename, destroying the existing image and leaving the database row pointing at a file that was never written. A mirror problem existed in deleteExistingImage(), where a failed Storage::delete() still nulled the model's image field, orphaning the file on disk. The condition is not directly attacker-controlled: it is triggered when any legitimate authenticated user submits an image upload while the storage backend transiently fails (for example an S3 network error, a local filesystem permission problem, or quota exhaustion). The result is unrecoverable loss of the prior image and a durable inconsistency between the database and disk that requires manual reconciliation. All models whose controllers route through ImageUploadRequest::handleImages (assets, asset models, users, companies, manufacturers, locations, categories, suppliers, departments, and other image-carrying models) are affected.
Statistical analysis made it clear that VulDB provides the best quality for vulnerability data.
Analysis
by VulDB Data Team • 09/09/2026
The vulnerability in Snipe-IT versions prior to the fix involves a critical race condition and improper error handling within the ImageUploadRequest::handleImages method, which is utilized by controllers for assets, asset models, users, companies, manufacturers, locations, categories, suppliers, departments, and other image-carrying entities. The core technical flaw lies in the sequence of operations during an image upload process where the application deletes the existing image file via deleteExistingImage() before successfully persisting the new one. If the storage backend experiences a transient failure such as an S3 network error, local filesystem permission issues, or quota exhaustion after the deletion but before the successful write operation, the previous image is irrecoverably lost while the database row continues to point at a filename that was never written to disk. This creates a durable inconsistency between the application's metadata and the actual file system state.
A secondary aspect of this vulnerability exists within the deleteExistingImage() function itself, where a failed Storage::delete operation still nullifies the model's image field in the database. In this scenario, although the original file remains on disk because the deletion did not complete successfully, the application no longer references it due to the cleared database record. This results in an orphaned file that consumes storage space without being accessible through the user interface or API, effectively causing data loss from a functional perspective and creating clutter within the storage backend. Both scenarios demonstrate a failure to implement atomic operations or proper rollback mechanisms when dealing with external storage dependencies.
From an operational impact standpoint, this vulnerability leads to unrecoverable loss of prior images for any authenticated user who attempts to upload a new image while the storage system is experiencing transient issues. Since the condition is not directly attacker-controlled in terms of triggering it maliciously, exploitation relies on environmental instability rather than direct code injection or logic bypassing by an adversary. However, this can be leveraged indirectly if an attacker with valid credentials repeatedly triggers uploads during periods of known infrastructure stress to cause denial of service through data loss and database corruption. The inconsistency requires manual reconciliation efforts by administrators to restore correct file-to-database mappings or recover lost assets from backups, impacting business continuity and operational efficiency.
This issue aligns with CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition, as the application checks for existing files and deletes them before verifying that the new upload was successful. It also relates to CWE-252: Unchecked Return Value, specifically regarding the failure to check if Storage::delete() succeeded before modifying the database state. In terms of MITRE ATT&CK, this vulnerability could be categorized under T1485: Data Destruction, although it is primarily a reliability and integrity issue rather than a malicious act unless exploited by insiders or through compromised accounts during system outages.
Mitigation strategies should focus on implementing atomic file operations where the new image is uploaded to a temporary location first, verified for successful write completion, and only then replacing the old reference in both storage and database simultaneously. Alternatively, applications can adopt a strategy of keeping multiple versions until the upload is fully confirmed, allowing rollback capabilities if errors occur. Ensuring robust error handling that does not modify persistent state unless all related operations succeed is crucial. Additionally, implementing retry logic with exponential backoff for transient network failures during uploads can reduce the likelihood of hitting these failure windows. Regular audits and automated reconciliation scripts should be employed to detect and fix any existing inconsistencies between database records and actual file storage states.