
PoC repository for CVE-2025-68147: Stored Cross-Site Scripting (XSS) in OpenSourcePOS. Vulnerability allows privilege escalation via malicious JavaScript injection in the Store Config module. Includes payload details and patch verification (v3.4.0). Security Researcher: Aditya Singh (Nixon-H).
| Metadata | Details |
|---|---|
| CVE ID | CVE-2025-68147 |
| Severity | High CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:N |
| Vulnerability Type | Stored Cross-Site Scripting (CWE-79) |
| Affected Versions | OpenSourcePOS v3.4.0, v3.4.1 |
| Patched Version | v3.4.2 |
| Vulnerable Component | Store Configuration Module (Return Policy field) |
| Reporter | Aditya Singh (Nixon-H) |
A Stored Cross-Site Scripting (XSS) vulnerability was discovered in the Store Configuration module of OpenSourcePOS. The application failed to properly sanitize user-supplied input in the "Return Policy" field before storing it in the ospos_app_config database table.
This flaw allowed an authenticated attacker with configuration privileges (or an attacker exploiting a separate CSRF chain) to inject arbitrary JavaScript payloads. Because the "Return Policy" is dynamically rendered on every sales receipt, the injected payload executes automatically in the browser of any user—including low-privileged cashiers, other administrators, or customers—whenever a receipt is generated or viewed.
The vulnerability resides in the receipt view template: app/Views/sales/receipt_default.php.
The application retrieves the "Return Policy" string from the global configuration array ($this->config['return_policy']) and prepares it for display.
nl2br() to convert newlines to HTML line breaks (<br>).nl2br() does not sanitize HTML special characters. It leaves tags like <script>, ``, and onload attributes completely intact.Vulnerable Code (Before Patch):
<div id="sale_return_policy">
<?php echo nl2br($this->config['return_policy']); ?>
</div>
When an admin saves the configuration, the payload is stored raw in the database.
ospos_app_configreturn_policyPolicy Text... <script>alert('XSS')</script>Because there is no input sanitization on the controller side (Config.php) and no output escaping on the view side (receipt_default.php), the application is vulnerable to Stored XSS.
The attack targets the Store Configuration panel but impacts the Sales/Receipt module.
http://[TARGET]/config (POST request to save config)http://[TARGET]/sales/receipt/[SALE_ID]Step 1: The Injection We logged in as an Administrator and navigated to Store Configuration -> General. In the "Return Policy" text area, we injected the following specific payload:
Standard Return Policy: No Refunds.
<script>alert('XSS_BY_NIXON_SUCCESSFUL')</script>
Step 2: Persistence
Upon clicking "Submit", the application sent a POST request to /config/save. The payload was successfully committed to the database.
Step 3: The Trigger To verify the impact on other users:
http://localhost/sales/receipt/1). The browser parses the return_policy div, encounters the <script> tag, and immediately executes the JavaScript.Observed Result:
A browser alert box appeared with the message: XSS_BY_NIXON_SUCCESSFUL.
Screenshot 1: The Alert Trigger
Screenshot 2: Payload in Configuration
🎥 Video Demonstration: Click to Download / Watch the PoC Video
This is a Scope Changed (S:C) vulnerability because the attack is stored on the server but executes in the victim's browser context.
/sales/receipt/105). The script executes silently, sending document.cookie (containing the ospos_session ID) to the attacker's server./employees/save.hacker / password123) is created instantly in the background. The victim sees nothing but the receipt, while the attacker gains a permanent backdoor.The vulnerability was fixed in OpenSourcePOS v3.4.2.
The maintainer applied a patch that implements Context-Aware Output Encoding. The configuration value is now wrapped in CodeIgniter's global esc() helper function before being passed to nl2br().
The Patch (Commit 22297a):
<div id="sale_return_policy">
<?php echo nl2br(esc($this->config['return_policy'])); ?>
</div>
Verification: After upgrading to v3.4.2, the same payload is rendered as harmless text:
Standard Return Policy: No Refunds. <script>alert('XSS_BY_NIXON_SUCCESSFUL')</script>
22297a) and verified by researcher.