{"id":"CVE-2026-42877","aliases":[],"url":"https://o3.security/vulnerability/CVE-2026-42877","summary":"FacturaScripts vulnerable to stored XSS via product reference in sales/purchases","details":"## Summary\n\nA stored Cross-Site Scripting (XSS) vulnerability exists in the product search modal of sales and purchases documents. An authenticated user with access to the warehouse module can create a product with a malicious reference that executes arbitrary JavaScript in the browser of any other user who opens the product search modal inside an invoice, order, or delivery note.\n\n## Affected files\n\n- `Core/Lib/AjaxForms/SalesModalHTML.php`\n- `Core/Lib/AjaxForms/PurchasesModalHTML.php`\n\n## Vulnerability details\n\nThe `referencia` field of a product variant is injected directly into an HTML `onclick` attribute string without JavaScript context escaping:\n\n```php\n// SalesModalHTML.php ~line 102\n$tbody .= '<tr onclick=\"return salesFormAction(\\'add-product\\', \\''\n    . $row['referencia']   // no htmlspecialchars() applied\n    . '\\');\">';\n```\n\nWhen a product is saved, `noHtml()` encodes `'` → `&#39;`. This appears safe in static HTML context. However, the modal HTML is later returned as a JSON response and inserted into the DOM via `innerHTML`:\n\n```javascript\n// SalesDocument.html.twig line 118\ndocument.getElementById(\"findProductList\").innerHTML = data.products;\n```\n\nThe browser HTML parser decodes `&#39;` → `'` during the `innerHTML` assignment, breaking out of the JavaScript string literal in the `onclick` attribute and executing the injected code.\n\n**Attack payload stored in database:** `x&#39;+alert(1)+&#39;`\n\n**Resulting `onclick` after `innerHTML` decode:**\n```javascript\nreturn salesFormAction('add-product', 'x'+alert(1)+'')\n//                                        ^^^^^^^^^^ executes before the function call\n```\n\n## Steps to reproduce\n\n**Step 1 — Inject the payload**\n\n1. Log in as a user with write access to Warehouse → Products\n2. Navigate to `/EditProducto` and create a new product with the following values:\n\n| Field | Value |\n|---|---|\n| Reference | `x'+alert(1)+'` |\n| Description | `test` |\n\n3. Save the product\n\n**Step 2 — Trigger the XSS**\n\n1. Make sure at least one customer exists in the system (Sales → Customers)\n2. Navigate to `/EditFacturaCliente?codcliente=<customer_code>`\n3. In the invoice form, click the product search button next to the \"Referencia\" field\n4. Click on the 'malicious' product `alert(1)`\n\n<img width=\"1162\" height=\"536\" alt=\"image\" src=\"https://github.com/user-attachments/assets/aaa2879e-c1fb-4af9-8501-bac03ca24ffe\" />\n\n\n## Impact\n\nAlthough session cookies (`fsLogkey`, `fsNick`) have the `HttpOnly` flag set and cannot be read directly via `document.cookie`, the injected script runs in the victim's authenticated browser context, meaning the attacker can make arbitrary authenticated requests on their behalf, create new admin users via AJAX POST to `/EditUser`, exfiltrate any business data visible in the DOM, or redirect the user to an external site. The most critical scenario is privilege escalation: a low-privilege employee with only warehouse\naccess can execute JavaScript in an administrator's session without knowing their password.\n\n## Recommended fix\n\nApply `htmlspecialchars()` with `ENT_QUOTES` before inserting `referencia` into the `onclick` attribute in both affected files.\n\n**`Core/Lib/AjaxForms/SalesModalHTML.php`**\n\n```php\n// Before (vulnerable):\n$tbody .= '<tr onclick=\"return salesFormAction(\\'add-product\\', \\''\n    . $row['referencia']\n    . '\\');\">';\n\n// After (safe):\n$tbody .= '<tr onclick=\"return salesFormAction(\\'add-product\\', \\''\n    . htmlspecialchars($row['referencia'], ENT_QUOTES, 'UTF-8')\n    . '\\');\">';\n```\n\n**`Core/Lib/AjaxForms/PurchasesModalHTML.php`**\n\nApply the same change to the equivalent line.\n\n**Why `ENT_QUOTES` is required:** `ENT_QUOTES` encodes both `\"` and `'` characters. This ensures that `'` is stored as `&#39;` and — critically — remains `&#39;` after `innerHTML` assignment, because `htmlspecialchars` produces a form that the HTML parser does not decode back into a raw quote inside a JS string context.\n\n**Alternative mitigation:** replace `innerHTML` with `innerText` or a DOM-based rendering approach that never parses injected strings as HTML. This would eliminate the entire class of HTML-injection-via-innerHTML vulnerabilities in the sales and purchases\nforms.\n\n## Credits\nOmar Ramirez","published":"2026-05-07T19:37:08Z","modified":"2026-09-10T03:50:55.300801632Z","cvss":{"score":5.4,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N"},"epss":{"score":0.00165,"percentile":0.05902,"asOf":"2026-08-24"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"Packagist","name":"facturascripts/facturascripts","fixedVersion":null}],"fix":null,"references":[{"type":"WEB","url":"https://github.com/NeoRazorX/facturascripts/security/advisories/GHSA-r736-2678-fcrx"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-42877"},{"type":"PACKAGE","url":"https://github.com/NeoRazorX/facturascripts"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-09-10T03:50:55.300801632Z"}}