OPNsense: Stored XSS über OpenVPN-common_name führt zu Root-RCE

Ein von einem RADIUS/LDAP-Backend kontrollierter OpenVPN-common_name bricht in den OPNsense-Status-Ansichten aus einem HTML-Attribut aus und führt Skript in der Root-Admin-Sitzung aus, was bis zur Root-Befehlsausführung eskaliert.

Advisory-ID: TP-2026-030
Produkt: OPNsense (Open-Source-Firewall- und Routing-Plattform)
Schwachstellentyp: Stored Cross-Site Scripting zu Root-RCE (CWE-79)
CVE: CVE-2026-58390
CVSS 3.1: 8.0 (Hoch) · CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:H
Betroffene Versionen: <= 26.1.10
Behoben in: 26.1.11
Hersteller-Advisory: GHSA-26cj-h9rj-g5pf
Gemeldet: 14. Juni 2026

Zusammenfassung

OPNsense ist eine weit verbreitete Open-Source-Firewall- und Routing-Plattform. Die OpenVPN-Verbindungsstatus-Ansichten (Dashboard-Widget und Status-Seite) rendern den client-common_name in ein HTML-Attribut, ohne das doppelte Anführungszeichen zu maskieren. Die MVC-Response-Schicht escaped API-Ausgaben mit htmlspecialchars(ENT_NOQUOTES), das <, > und & kodiert, aber nicht ". Ist ein OpenVPN-Server mit username-as-common-name und einem RADIUS- oder LDAP-Backend konfiguriert, entspricht der common_name dem angreiferseitig gewählten Login-Benutzernamen. Ein "-haltiger Benutzername bricht aus dem Attribut aus und wird zu einem aktiven Event-Handler, der im Browser des Root-Admins läuft, sobald dieser die Ansicht öffnet. turingpoint hat den vollständigen Ablauf verifiziert und gemeldet; der Hersteller hat ihn in 26.1.11 behoben.

Ursache

OpenVPNClients.js interpoliert data-common-name="${client.common_name}" roh via .append(). Die API-Ausgabe wird von der MVC-Response-Schicht (Mvc/Response.php) per htmlspecialchars($result, ENT_NOQUOTES) maskiert, das <, > und & kodiert, das doppelte Anführungszeichen aber unberührt lässt. Mit username-as-common-name (openvpn.inc) ist der common_name gleich dem rohen Client-Auth-Benutzernamen, den user_pass_verify.php unsanitisiert durchreicht. Die Local-DB blockiert Anführungszeichen über die Maske [a-z0-9._-] in UsernameField.php, RADIUS- und LDAP-Benutzernamen umgehen diese Prüfung jedoch. Das Skript läuft in der Dashboard-Sitzung des Admins, und die OPNsense-Admin-GUI steuert configd als Root.

Proof of Concept

# 1. OpenVPN-Server mit username-as-common-name + RADIUS/LDAP-Backend.
# 2. Angreifer registriert im Verzeichnis einen Benutzernamen mit "-Ausbruch:

    x" onmouseover="window.xssfired=1" data-z="

# 3. Angreifer baut einen OpenVPN-Tunnel auf; der common_name wird in der
#    Sitzungsliste gespeichert.
# 4. Admin öffnet Dashboard-Widget oder Verbindungsstatus-Seite:

    data-common-name="x" onmouseover="window.xssfired=1" data-z=""

#    -> das Attribut bricht auf, der Event-Handler feuert in der Root-Admin-Sitzung.

# 5. Eskalation aus dem XSS-Kontext:
    - vollständiger Diebstahl von /conf/config.xml (Credentials, Keys, PSKs)
    - Root-Befehlsausführung über configd
    - Root-Passwort-Reset via POST /api/auth/user/set -> SSH als uid=0(root)

Live-verifiziert auf realem OPNsense (headless Chrome): Der echte OpenVPN-Tunnel erhält das " im common_name, die Sitzungssuche gibt es ungefiltert zurück, der DOM-Ausbruch setzt window.xssfired=1, und aus der Admin-Sitzung reproduziert die Root-Kette bis uid=0(root).

Auswirkung

  • Skriptausführung in der Root-Admin-Sitzung, sobald ein Admin die OpenVPN-Status-Ansicht öffnet.
  • Vollständiger Diebstahl der /conf/config.xml (Zugangsdaten, Schlüssel, Pre-Shared-Keys).
  • Root-Befehlsausführung über configd und Root-Passwort-Reset via POST /api/auth/user/set, damit SSH-Zugang als root.
  • Persistente Ausnutzung, da der bösartige Benutzername gespeichert bleibt.

Referenzen

Steckt so etwas in Ihrer Software?

Diese Schwachstelle hat unser Team im Rahmen seiner Arbeit gefunden. Lassen Sie Ihre Anwendungen von denselben Spezialisten prüfen, mit einem Penetrationstest von turingpoint.