VYPR
Moderate severityNVD Advisory· Published Aug 21, 2025· Updated Aug 21, 2025

UnoPim Stored XSS via SVG MIME/Sanitizer Bypass

CVE-2025-55742

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.

PackageAffected versionsPatched versions
unopim/unopimPackagist
< 0.2.10.2.1

Affected products

2
  • UnoPim/UnoPimllm-fuzzy
    Range: <0.2.1
  • unopim/unopimv5
    Range: < 0.2.1

Patches

3
49d5f6ac4d5d

fix: add validation for file extension and mime

https://github.com/unopim/unopimdevansh.pal507Apr 1, 2025via ghsa
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',
         ];
     
         /**
    
b5e169e65725

fix: Add FileMimeExtensionMatch rule for file

https://github.com/unopim/unopimdevansh.pal507Mar 28, 2025via ghsa
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;
    +    }
    +}
    
b596021b5a5e

fix: add validation for user image mime type

https://github.com/unopim/unopimdevansh.pal507Mar 27, 2025via ghsa
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

News mentions

0

No linked articles in our index yet.