A browser trips over an empty chair at the end of a media list
libcss through 0.9.2, the CSS parsing library used by NetSurf and a handful of other lightweight consumers, crashes when a stylesheet's @media or @import media list ends with a trailing comma (e.g., @media screen, { ... }). The mq_parse_media_query() function fails to validate the list before dereferencing a NULL pointer, causing the host application to terminate. The attacker only needs to serve a malicious stylesheet and convince the victim to load it.
Vendor severity is listed as MEDIUM (6.5) with CVSS 3.1 and HIGH (7.1) under CVSS 4.0, but that overstates real-world enterprise risk. The affected component is a niche browser/renderer library with little to no presence in mainstream enterprise fleets. The impact is a self-contained process crash: no code execution, no data loss, no privilege escalation, and the user can simply restart the application. In practice this is a LOW severity nuisance, not a fleet-level threat.
4 steps from start to impact.
Attacker crafts malicious CSS
@media or @import rule whose media list ends with a trailing comma — e.g., @media screen, { body { color: red; } }. This malformed syntax is the trigger for the NULL dereference.- Attacker can host a file or inject CSS into a page the victim will load
- Requires luring a victim to a malicious URL or embedding the CSS in a page the victim visits
- No autonomous propagation; the attacker must actively deliver the content
Victim opens the malicious content with a libcss-linked application
- Victim has a libcss consumer (NetSurf, embedded renderer) installed
- Victim performs a user action — clicking a link or opening a local file
- NetSurf and libcss consumers are extremely rare in enterprise environments
- Default enterprise browsers (Chrome, Edge, Firefox) do not use libcss and are unaffected
- The user must be convinced to open the page; no silent exploitation
mq_parse_media_query() dereferences a NULL pointer on the trailing comma
mq_parse_media_query() fails to check for a valid media query after the comma, attempts to use a NULL pointer, and triggers a segmentation fault, crashing the entire process.- Exact malformed syntax reaches the vulnerable parser code path
- libcss version ≤ 0.9.2 is linked
- The crash requires a very specific input; normal browsing rarely produces this pattern
- No exploit chain beyond the crash — the process terminates, but no memory corruption or control flow hijack occurs
Application terminates; availability impact is limited to the user session
- The application does not sandbox the renderer process in a way that prevents the crash
- User continues using the vulnerable version
- Impact is non-persistent and limited to one process
- No system-level availability loss, no multi-user impact, no service outage
- Restarting the application fully recovers
- Web application firewalls (WAFs) and network IDS cannot detect malformed CSS inside HTTPS traffic — they do not parse CSS media lists.
- Disabling JavaScript does not prevent this crash; the trigger is a stylesheet parsing flaw in libcss, not script execution.
The supporting signals.
| In-the-wild status | No known exploitation; not listed in CISA KEV; no active campaigns observed. |
|---|---|
| Proof-of-concept | No public PoC found on GitHub or pocindex.io; VulDB states no exploit available. |
| EPSS | 0.00327 (very low — well below the typical threshold for prioritization). |
| KEV status | Not listed as of 2026-10-26. |
| CVSS 3.1 | 6.5 Medium — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H |
| CVSS 4.0 (VulnCheck) | 7.1 High — CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N |
| Affected versions | libcss 0 through 0.9.2, inclusive. |
| Fixed version | Not yet specified in any advisory; upgrade beyond 0.9.2 once a patch is released. |
| Scanning/exposure | No Shodan/Censys internet exposure data — this is a client-side library, not a network service. |
| Disclosure / assigner | Published 2026-10-26 by VulnCheck (CNA); MITRE record available on NVD. |
Sources.
Why this verdict
- Friction audit: Every step of the chain requires the victim to open a malicious page with a niche libcss consumer (NetSurf). That combination is rare in enterprise fleets; default browsers are unaffected.
- Role multiplier: libcss's realistic roles are user-facing browser/renderer or embedded in low-value utilities. No plausible deployment as IdP, hypervisor, secret manager, CI/CD, backup, or network edge exists, and the documented chain yields only a process crash — so the verdict floor does not engage.
- Impact ceiling: CWE-476 leads only to availability loss (DoS) of the consumer process; no code execution, privilege escalation, or data exposure is possible. Repeated crashing is recoverable.
- No exploitation: EPSS 0.00327, no KEV listing, no public PoC, and no in-the-wild reports. Threat maturity is negligible.
Why not higher?
Not HIGH or CRITICAL because there is no code execution, no privilege escalation, no data confidentiality/integrity impact, and the affected component is not widely deployed. The vendor Medium CVSS already assumes user interaction; the real-world niche user base and lack of any exploitation activity push this down to LOW.
Why not lower?
Not IGNORE because affected versions have no fixed release declared yet, and a malicious webpage can still crash the application repeatedly. It remains a hygiene issue for any organization that uses NetSurf or embedded libcss.
Crowdsourced verification payload.
Run on any Linux/macOS host where an application may link against libcss (e.g., NetSurf). Invoke: bash check_libcss_cve-2026-116740.sh. No special privileges are required to read package metadata, but root may be needed to inspect all libraries.
#!/usr/bin/env bash
# Check for CVE-2026-116740 vulnerable libcss <= 0.9.2
set -u
VULN_MAX="0.9.2"
# Try pkg-config first
if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists libcss 2>/dev/null; then
VER=$(pkg-config --modversion libcss)
elif command -v dpkg >/dev/null 2>&1; then
VER=$(dpkg-query -W -f='${Version}' libcss 2>/dev/null || true)
elif command -v rpm >/dev/null 2>&1; then
VER=$(rpm -q --qf '%{VERSION}' libcss 2>/dev/null || true)
else
echo "UNKNOWN"
exit 3
fi
if [ -z "$VER" ]; then
echo "UNKNOWN"
exit 3
fi
# Strip non-numeric suffixes like -1 or -deb
VER_NUM=$(echo "$VER" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+' | head -1)
if [ -z "$VER_NUM" ]; then
echo "UNKNOWN (unparseable version: $VER)"
exit 3
fi
# Compare versions using sort -V
if [ "$(printf '%s\n%s\n' "$VULN_MAX" "$VER_NUM" | sort -V | head -1)" = "$VER_NUM" ]; then
echo "VULNERABLE (libcss $VER_NUM)"
exit 1
else
echo "PATCHED (libcss $VER_NUM)"
exit 0
fi