Cross-site Scripting (XSS) - Stored in snipe/snipe-it
Description
Cross-site Scripting (XSS) - Stored in GitHub repository snipe/snipe-it prior to v6.2.2.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Stored XSS in Snipe-IT asset history allows authenticated attackers to inject arbitrary JavaScript via location name fields.
Vulnerability
Overview
CVE-2023-5452 is a stored cross-site scripting (XSS) vulnerability in Snipe-IT, an open-source IT asset management system. The root cause lies in the asset history component, where location names (old and new values) were rendered without proper escaping. The commit that fixes the issue [2] shows the addition of the e() helper function to escape output, confirming that unsanitized user-controlled data was being stored and later displayed in the web interface.
Exploitation
An authenticated user with permission to edit asset details—specifically the location fields—can inject malicious JavaScript into the location name. When other users (including administrators) view the asset history, the injected script executes in their browser. No special network access is required beyond normal web application usage; the attacker simply needs to be able to modify asset metadata [1][3].
Impact
Successful exploitation allows the attacker to execute arbitrary JavaScript in the context of the victim's session. This can lead to session hijacking, credential theft, unauthorized actions performed on behalf of the victim, or defacement of the application interface. The stored nature of the XSS means the payload persists and affects all subsequent viewers of the affected asset history.
Mitigation
The vulnerability is fixed in Snipe-IT version 6.2.2. Users are strongly advised to upgrade immediately. The fix is visible in the referenced commit [2], which escapes location name values before rendering. No workarounds have been publicly documented; upgrading is the recommended course of action. The issue was reported via the huntr.dev bug bounty platform [4].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
snipe/snipe-itPackagist | < 6.2.2 | 6.2.2 |
Affected products
2- snipe/snipe/snipe-itv5Range: unspecified
Patches
1eea2eabaeef1Escaping asset history old/new values
1 file changed · +13 −11
app/Http/Transformers/ActionlogsTransformer.php+13 −11 modified@@ -178,24 +178,26 @@ public function changedInfo(array $clean_meta) if(array_key_exists('rtd_location_id',$clean_meta)) { - $clean_meta['rtd_location_id']['old'] = $clean_meta['rtd_location_id']['old'] ? "[id: ".$clean_meta['rtd_location_id']['old']."] ". $location->find($clean_meta['rtd_location_id']['old'])->name : trans('general.unassigned'); - $clean_meta['rtd_location_id']['new'] = $clean_meta['rtd_location_id']['new'] ? "[id: ".$clean_meta['rtd_location_id']['new']."] ". $location->find($clean_meta['rtd_location_id']['new'])->name : trans('general.unassigned'); + $clean_meta['rtd_location_id']['old'] = $clean_meta['rtd_location_id']['old'] ? "[id: ".$clean_meta['rtd_location_id']['old']."] ". e($location->find($clean_meta['rtd_location_id']['old'])->name) : trans('general.unassigned'); + $clean_meta['rtd_location_id']['new'] = $clean_meta['rtd_location_id']['new'] ? "[id: ".$clean_meta['rtd_location_id']['new']."] ". e($location->find($clean_meta['rtd_location_id']['new'])->name) : trans('general.unassigned'); $clean_meta['Default Location'] = $clean_meta['rtd_location_id']; unset($clean_meta['rtd_location_id']); } - if(array_key_exists('location_id', $clean_meta)) { - $clean_meta['location_id']['old'] = $clean_meta['location_id']['old'] ? "[id: ".$clean_meta['location_id']['old']."] ".$location->find($clean_meta['location_id']['old'])->name : trans('general.unassigned'); - $clean_meta['location_id']['new'] = $clean_meta['location_id']['new'] ? "[id: ".$clean_meta['location_id']['new']."] ".$location->find($clean_meta['location_id']['new'])->name : trans('general.unassigned'); + + if (array_key_exists('location_id', $clean_meta)) { + $clean_meta['location_id']['old'] = $clean_meta['location_id']['old'] ? "[id: ".$clean_meta['location_id']['old']."] ".e($location->find($clean_meta['location_id']['old'])->name): trans('general.unassigned'); + $clean_meta['location_id']['new'] = $clean_meta['location_id']['new'] ? "[id: ".$clean_meta['location_id']['new']."] ".e($location->find($clean_meta['location_id']['new'])->name) : trans('general.unassigned'); $clean_meta['Current Location'] = $clean_meta['location_id']; unset($clean_meta['location_id']); } + if(array_key_exists('model_id', $clean_meta)) { $oldModel = $model->find($clean_meta['model_id']['old']); - $oldModelName = $oldModel->name ?? trans('admin/models/message.deleted'); + $oldModelName = $oldModel ? e($oldModel->name) : trans('admin/models/message.deleted'); $newModel = $model->find($clean_meta['model_id']['new']); - $newModelName = $newModel->name ?? trans('admin/models/message.deleted'); + $newModelName = $newModel ? e($newModel->name) : trans('admin/models/message.deleted'); $clean_meta['model_id']['old'] = "[id: ".$clean_meta['model_id']['old']."] ".$oldModelName; $clean_meta['model_id']['new'] = "[id: ".$clean_meta['model_id']['new']."] ".$newModelName; /** model is required at asset creation */ @@ -206,10 +208,10 @@ public function changedInfo(array $clean_meta) if(array_key_exists('company_id', $clean_meta)) { $oldCompany = $company->find($clean_meta['company_id']['old']); - $oldCompanyName = $oldCompany->name ?? trans('admin/companies/message.deleted'); + $oldCompanyName = $oldCompany ? e($oldCompany->name) : trans('admin/company/message.deleted'); $newCompany = $company->find($clean_meta['company_id']['new']); - $newCompanyName = $newCompany->name ?? trans('admin/companies/message.deleted'); + $newCompanyName = $newCompany ? e($newCompany->name) : trans('admin/company/message.deleted'); $clean_meta['company_id']['old'] = $clean_meta['company_id']['old'] ? "[id: ".$clean_meta['company_id']['old']."] ". $oldCompanyName : trans('general.unassigned'); $clean_meta['company_id']['new'] = $clean_meta['company_id']['new'] ? "[id: ".$clean_meta['company_id']['new']."] ". $newCompanyName : trans('general.unassigned'); @@ -219,10 +221,10 @@ public function changedInfo(array $clean_meta) if(array_key_exists('supplier_id', $clean_meta)) { $oldSupplier = $supplier->find($clean_meta['supplier_id']['old']); - $oldSupplierName = $oldSupplier->name ?? trans('admin/suppliers/message.deleted'); + $oldSupplierName = $oldSupplier ? e($oldSupplier->name) : trans('admin/suppliers/message.deleted'); $newSupplier = $supplier->find($clean_meta['supplier_id']['new']); - $newSupplierName = $newSupplier->name ?? trans('admin/suppliers/message.deleted'); + $newSupplierName = $newSupplier ? e($newSupplier->name) : trans('admin/suppliers/message.deleted'); $clean_meta['supplier_id']['old'] = $clean_meta['supplier_id']['old'] ? "[id: ".$clean_meta['supplier_id']['old']."] ". $oldSupplierName : trans('general.unassigned'); $clean_meta['supplier_id']['new'] = $clean_meta['supplier_id']['new'] ? "[id: ".$clean_meta['supplier_id']['new']."] ". $newSupplierName : trans('general.unassigned');
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.