high · 8.2CVE-2026-63135Aug 21, 2026

CVE-2026-63135: YOURLS Stored XSS via Crafted Referer Header in Statistics Chart

Rohit Hatagale
AI Security Researcher, SecureLayer7

An unauthenticated attacker can poison a YOURLS short link's referrer log with a crafted HTTP Referer header, causing arbitrary JavaScript to execute in an administrator's browser when they view that…

Packageyourls/yourls
Ecosystemcomposer
Affected>= 1.5.1, <= 1.10.3
Fixed in1.10.4
CVE-2026-63135: YOURLS Stored XSS via Crafted Referer Header in Statistics Chart

The problem

YOURLS records the HTTP Referer header on every redirect and later displays aggregated referrer domains inside a Google Charts JavaScript block on the per-link stats page.

The function yourls_google_array_to_data_table() in includes/functions-infos.php concatenates those domain labels directly into an inline <script> as ['$label', ...] with no JavaScript-string escaping. yourls_sanitize_url_safe() removes some characters but deliberately allows ', [, ], ,, and parentheses, so a crafted hostname breaks out of the JS string context and injects arbitrary code.

The stored payload executes in the admin origin whenever an authenticated user opens the stats page, giving the attacker full same-origin access including CSRF token theft and privileged API calls.

Proof of concept

A working proof-of-concept for CVE-2026-63135 in yourls/yourls, with the exact payload below.

bash
curl -H "Referer: http://x',1],['marker',alert(document.domain)],['z.tld/path" \
  http://localhost/<existing-keyword>

# Then visit the stats page to trigger execution:
# http://localhost/<existing-keyword>+

# The crafted host survives sanitization and renders into the chart script as:
# var data = google.visualization.arrayToDataTable([
#     ['x',1],['marker',alert(document.domain)],['z.tld',1]
# ]);

The sink is yourls_google_array_to_data_table(), which builds a JS array literal by string-concatenating unsanitized labels: "['" . $label . "', " . $count . "]". A hostname containing ',1],['marker',alert(1)],['z.tld closes the current array element, injects a new element whose value is a function call, and reopens the array, all within valid JS syntax.

yourls_sanitize_url_safe() is URL-focused and intentionally keeps characters like single quotes and parentheses that are valid in URLs. Those same characters are JS string and expression metacharacters, so sanitization that is correct for URL storage is insufficient for JavaScript embedding.

The fix in PR #4107 (commit e1e93476) adds JS-string escaping (at minimum backslash-escaping single quotes and backslashes) to labels before they are concatenated into the chart script, closing the string-breakout vector. CWE-79: Improper Neutralization of Input During Web Page Generation.

The fix

Upgrade to YOURLS 1.10.4. The patch is in commit e1e93476655107e6caab34e52259eb1c91079ec7 (PR #4107). If you cannot upgrade immediately, disable public statistics pages (YOURLS_PRIVATE_INFOS should not be set to false) to limit exposure to authenticated users only, and audit any plugins that call yourls_stats_pie() or yourls_google_array_to_data_table() directly.

Reported by Thai Son Dinh, VinSOC Labs (R&D).

References: [1][2][3][4][5]

Related research