UnoPim Stored XSS via SVG MIME/Sanitizer Bypass
Description
UnoPim is an open-source Product Information Management (PIM) system built on the Laravel framework. Before 0.2.1, UnoPim contains a stored cross-site scripting vulnerability via SVG MIME/sanitizer bypass in the /admin/settings/users/create endpoint. This vulnerability is fixed in 0.2.1.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
UnoPim before 0.2.1 has a stored XSS via SVG MIME/sanitizer bypass on the user creation endpoint, allowing arbitrary script execution.
Vulnerability
Overview
The stored cross-site scripting (XSS) vulnerability in UnoPim (before version 0.2.1) originates from an insufficient file upload sanitization in the /admin/settings/users/create endpoint. Specifically, the application's Sanitizer trait validates allowed MIME types by inspecting the Content-Type header, but does not properly verify the actual file content beyond the initial magic bytes [1][2]. This allows an attacker to craft a file that presents a GIF magic byte prefix (e.g., GIF89a) while containing SVG markup, causing the sanitizer to misidentify it as a benign GIF and bypass the intended SVG MIME restrictions [2].
Attack
Vector & Prerequisites
Exploitation requires an authenticated user with access to the user creation interface (admin panel). The attacker uploads a file with a manipulated MIME type and content, such as a .svg file prepended with GIF89a magic bytes, under the image field during user creation [2]. Since the sanitizer only checks the MIME header and not the full file structure, the SVG content passes through unsanitized and is stored on the server. The stored SVG can include event handlers like onload or onmouseover, which execute when the payload is rendered in a victim's browser [2].
Impact
If triggered, the malicuous SVG executes arbitrary JavaScript in the context of the victim's session. This can lead to session hijacking, data theft, or administrative actions performed on behalf of the victim. The vulnerability is particularly severe because the user creation page is typically accessed by administrators, amplifying the potential for privilege escalation or full compromise of the PIM system [1][2].
Mitigation
Status
The issue is confirmed fixed in UnoPim version 0.2.1. The patch, implemented in commit b5e169e65725e0d80b6c79d57e62a25e1af6a3c3, introduces a FileMimeExtensionMatch validation rule that verifies the actual file extension and MIME type against the file content, preventing the MIME bypass [4]. Users are strongly advised to upgrade to 0.2.1 or later; no workarounds are documented for earlier versions.
AI Insight generated on May 19, 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 |
|---|---|---|
unopim/unopimPackagist | < 0.2.1 | 0.2.1 |
Affected products
2- unopim/unopimv5Range: < 0.2.1
Patches
349d5f6ac4d5dfix: add validation for file extension and mime
4 files changed · +19 −7
packages/Webkul/Admin/src/Http/Controllers/Settings/DataTransfer/ImportController.php+1 −0 modified@@ -166,6 +166,7 @@ public function update(int $id) 'allowed_errors', 'field_separator', 'images_directory_path', + 'file', 'filters', ]), [
packages/Webkul/Admin/src/Http/Controllers/Settings/UserController.php+2 −0 modified@@ -283,6 +283,8 @@ private function prepareUserData(UserForm $request, $id) return $this->cannotChangeRedirectResponse('role'); } + unset($data['image']); + return $data; }
packages/Webkul/DataTransfer/src/Validators/JobInstances/Import/CategoryJobValidator.php+8 −3 modified@@ -2,6 +2,7 @@ namespace Webkul\DataTransfer\Validators\JobInstances\Import; +use Webkul\Core\Rules\FileMimeExtensionMatch; use Webkul\DataTransfer\Rules\SeparatorTypes; use Webkul\DataTransfer\Validators\JobInstances\Default\JobValidator; @@ -12,9 +13,13 @@ class CategoryJobValidator extends JobValidator */ public function getRules(array $options): array { - if (isset($options['id'])) { - $this->rules['file'] = 'mimes:csv,xls,xlsx,txt'; - } + $this->rules['file'] = [ + empty($options['id']) ? 'required' : 'nullable', + 'mimes:csv,txt,xlsx,xls', + 'extensions:csv,xlsx,xls', + new FileMimeExtensionMatch, + ]; + $this->rules['field_separator'] = ['required', new SeparatorTypes]; return $this->rules;
packages/Webkul/DataTransfer/src/Validators/JobInstances/Import/ProductJobValidator.php+8 −4 modified@@ -2,6 +2,7 @@ namespace Webkul\DataTransfer\Validators\JobInstances\Import; +use Webkul\Core\Rules\FileMimeExtensionMatch; use Webkul\DataTransfer\Rules\SeparatorTypes; use Webkul\DataTransfer\Validators\JobInstances\Default\JobValidator; @@ -12,9 +13,13 @@ class ProductJobValidator extends JobValidator */ public function getRules(array $options): array { - if (isset($options['id'])) { - $this->rules['file'] = 'mimes:csv,xls,xlsx,txt'; - } + $this->rules['file'] = [ + empty($options['id']) ? 'required' : 'nullable', + 'mimes:csv,txt,xlsx,xls', + 'extensions:csv,xlsx,xls', + new FileMimeExtensionMatch, + ]; + $this->rules['field_separator'] = ['required', new SeparatorTypes]; return $this->rules; @@ -27,7 +32,6 @@ public function getRules(array $options): array 'action' => 'required:in:append,delete', 'validation_strategy' => 'required:in:stop-on-errors,skip-errors', 'allowed_errors' => 'required|integer|min:0', - 'file' => 'required|mimes:csv,xls,xlsx,txt', ]; /**
b5e169e65725fix: Add FileMimeExtensionMatch rule for file
3 files changed · +76 −15
packages/Webkul/Admin/src/Http/Requests/UserForm.php+7 −1 modified@@ -5,6 +5,7 @@ use Illuminate\Foundation\Http\FormRequest; use Webkul\Core\Repositories\LocaleRepository; use Webkul\Core\Rules\AlphaNumericSpace; +use Webkul\Core\Rules\FileMimeExtensionMatch; class UserForm extends FormRequest { @@ -43,7 +44,12 @@ public function rules() 'ui_locale_id' => 'required', 'role_id' => 'required', 'timezone' => 'required', - 'image.*' => 'sometimes|image|mimes:jpeg,png,jpg,gif,svg|max:2048', + 'image.*' => [ + 'sometimes', + 'image', + 'mimes:jpeg,png,jpg,svg,gif', + new FileMimeExtensionMatch, + ], ]; } }
packages/Webkul/Core/src/Resources/lang/en_US/validation.php+15 −14 modified@@ -1,18 +1,19 @@ <?php return [ - 'address' => 'The :attribute can only accept alpha, numeric, spaces, comma and dashes.', - 'alpha-numeric-space' => 'The :attribute can only accept alpha, numeric and spaces.', - 'code' => 'The :attribute must be valid and can only contain alphanumeric characters (letters and numbers).', - 'decimal' => 'The :attribute must be valid.', - 'phone-number' => 'The :attribute must be valid phone number.', - 'slug' => 'The :attribute must be valid slug.', - 'comma-separated-integer' => 'The :attribute field must be numeric and may contain comma.', - 'type' => 'The :attribute must be valid type.', - 'validation-type' => 'The :attribute must be valid type.', - 'field-option-not-found' => 'The :attribute contains invalid option(s) :invalid_codes.', - 'boolean-string' => 'The :attribute must be a boolean string represented as "true" or "false"', - 'not-supported' => 'The :attribute does not support the following values (:unsupported).', - 'seperator-not-supported' => 'Only , or ; or | is supported as a seperator.', - 'file-type' => 'The file must be of type csv,xls,xlsx', + 'address' => 'The :attribute can only accept alpha, numeric, spaces, comma and dashes.', + 'alpha-numeric-space' => 'The :attribute can only accept alpha, numeric and spaces.', + 'code' => 'The :attribute must be valid and can only contain alphanumeric characters (letters and numbers).', + 'decimal' => 'The :attribute must be valid.', + 'phone-number' => 'The :attribute must be valid phone number.', + 'slug' => 'The :attribute must be valid slug.', + 'comma-separated-integer' => 'The :attribute field must be numeric and may contain comma.', + 'type' => 'The :attribute must be valid type.', + 'validation-type' => 'The :attribute must be valid type.', + 'field-option-not-found' => 'The :attribute contains invalid option(s) :invalid_codes.', + 'boolean-string' => 'The :attribute must be a boolean string represented as "true" or "false"', + 'not-supported' => 'The :attribute does not support the following values (:unsupported).', + 'seperator-not-supported' => 'Only , or ; or | is supported as a seperator.', + 'file-type' => 'The file must be of type csv,xls,xlsx', + 'file-mime-extension-mismatch' => 'The file extension and mime type do not match. The file extension is :extension and the mime type is :mimeType.', ];
packages/Webkul/Core/src/Rules/FileMimeExtensionMatch.php+54 −0 added@@ -0,0 +1,54 @@ +<?php + +namespace Webkul\Core\Rules; + +use Closure; +use Illuminate\Contracts\Validation\ValidationRule; +use Illuminate\Http\File; +use Illuminate\Http\UploadedFile; +use Symfony\Component\Mime\MimeTypes; + +class FileMimeExtensionMatch implements ValidationRule +{ + /** + * Validate the file extension and mime type match. + * + */ + public function validate(string $attribute, mixed $value, Closure $fail): void + { + if (! $this->isValidFileInstance($value)) { + $fail('validation.file')->translate(); + + return; + } + + $extension = $value instanceof UploadedFile ? $value->getClientOriginalExtension() : $value->getExtension(); + + $mimeType = $value->getMimeType(); + + $mimeTypes = MimeTypes::getDefault()->getMimeTypes($extension); + + if (empty($mimeTypes)) { + $fail(trans('core::validation.file-mime-extension-mismatch', ['extension' => $extension, 'mimeType' => $mimeType])); + + return; + } + + if (! (in_array($mimeType, $mimeTypes) && $value->guessExtension() === $extension)) { + $fail(trans('core::validation.file-mime-extension-mismatch', ['extension' => $extension, 'mimeType' => $mimeType])); + + return; + } + } + + /** + * Check that the given value is a valid file instance. + * + * @param mixed $value + * @return bool + */ + public function isValidFileInstance($value) + { + return ($value instanceof UploadedFile && $value->isValid()) || $value instanceof File; + } +}
b596021b5a5efix: add validation for user image mime type
1 file changed · +1 −0
packages/Webkul/Admin/src/Http/Requests/UserForm.php+1 −0 modified@@ -43,6 +43,7 @@ public function rules() 'ui_locale_id' => 'required', 'role_id' => 'required', 'timezone' => 'required', + 'image.*' => 'sometimes|image|mimes:jpeg,png,jpg,gif,svg|max:2048', ]; } }
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-xr97-25v7-hc2qghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-55742ghsaADVISORY
- drive.proton.me/urls/KCKTSWHA3CghsaWEB
- github.com/unopim/unopim/blob/a0dc81947a59ada69e19e1e4313dd591d4e277b4/packages/Webkul/Core/src/Traits/Sanitizer.phpghsaWEB
- github.com/unopim/unopim/commit/49d5f6ac4d5d9ef7d9cdfe01853234d531c55f75ghsax_refsource_MISCWEB
- github.com/unopim/unopim/commit/b596021b5a5e0656abe16c01ae0e84c95f9fe902ghsax_refsource_MISCWEB
- github.com/unopim/unopim/commit/b5e169e65725e0d80b6c79d57e62a25e1af6a3c3ghsax_refsource_MISCWEB
- github.com/unopim/unopim/security/advisories/GHSA-xr97-25v7-hc2qghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.