Semantic MediaWiki's Special:FacetedSearch cstate hidden inputs enable reflected XSS (residual of CVE-2025-10354)
GHSA-9rcc-pmj8-ffhr is a medium-severity vulnerability with a CVSS 3.1 base score of 6.1, classed as Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79), in mediawiki/semantic-media-wiki (Packagist). Affected versions: >= 4.2.0, <= 7.2.0. It is fixed in 7.2.1.
Published 18 Sept 2026Updated 18 Sept 2026
- CVE ID
- No CVE assigned
- GHSA ID
- GHSA-9rcc-pmj8-ffhr
- EPSS
- Not scored
- Weakness (CWE)
- CWE-79Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
- KEV status
- Not in KEV
- Published
- 18 Sept 2026
- Updated
- 18 Sept 2026
- Ecosystem
- Packagist (PHP)
Summary
Source: OSV (GitHub advisory)
Special:FacetedSearch cstate hidden inputs enable reflected XSS (residual of CVE-2025-10354)
Details
Affected versions and vulnerable location
- Confirmed present on latest shipped release tag available in the local clone:
SemanticMediaWiki/SemanticMediaWiki@7.2.0. - Confirmed present on default branch
masterat HEAD18f418b4cdf2875e67a741349179a22c1573f61c.
Vulnerable sink (default-branch representation):
src/MediaWiki/Specials/FacetedSearch/HtmlBuilder.php:131-133- Builds
$hiddenby concatenating unescaped request-controlledcstate[$key]values into an HTML attribute context (value="...").
- Builds
templates/FacetedSearch/search.mustache:25- Inserts the constructed fragment via
{{{hidden}}}(no HTML escaping at this boundary).
- Inserts the constructed fragment via
Reachability trace (verified from source)
- HTTP entrypoint:
GETtoSpecial:FacetedSearchdispatches intoSMW\MediaWiki\Specials\SpecialFacetedSearch::execute().
- Request decoding boundary:
SpecialFacetedSearch::execute()constructsUrlArgsfrom$request->getValues()and callsParametersProcessor::checkRequest($request).
- Checksum gate:
ParametersProcessor::checkRequest()clearscstateonly whenfiltered != 1andgetInt('csum', 0) != crc32(getVal('q', '')).
- Decoder -> HTML assembly:
HtmlBuilder::buildHTML()iteratesforeach ( $urlArgs->getArray( 'cstate' ) as $key => $value )and concatenates each into$hiddenwithout escaping.HtmlBuilder::buildHTML()passes$hiddeninto the template variablehidden.
- HTML injection sink:
templates/FacetedSearch/search.mustacherenders{{{hidden}}}into the<form>, so the concatenated markup is inserted as raw HTML.
PoC
Reproduction steps (source-derived)
- Choose a
qvalue. - Compute
csumascrc32(q). - Send a request that includes:
q=<chosen>csum=<crc32(q)>- at least one
cstate[<key>]=<payload>entry
Example request shape:
/index.php/Special:FacetedSearch?q=Text&csum=<crc32(Text)>&cstate[0]=x%22%20autofocus%20onfocus%3Dalert(1)%20x%22
Impact
Attacker model
- Any remote attacker who can send HTTP requests to
Special:FacetedSearch(or the localized alias mapped to the sameSpecialFacetedSearchclass) can supply attacker-controlled query parameters. - Preconditions:
- The attacker must make
cstatesurviveParametersProcessor::checkRequest(), either by settingcsumtocrc32(q)(whenfiltered != 1), or by settingfiltered=1. - The attacker must supply
cstate[<key>]values containing characters that break out of the HTMLvalue="..."attribute context (for example an injected"to terminate the attribute value).
- The attacker must make
Severity and CVSS reasoning
Proposed severity: MEDIUM.
Proposed CVSS v3.1 vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N.
Rationale:
- AV:N: delivered over the network via query parameters.
- AC:L: requires only setting
q,csum, and at least onecstateentry. - PR:N: no authentication required for the request path in this code.
- UI:R: the victim must load the crafted URL.
- S:C: reflected XSS executes in the wiki origin and can affect other users depending on deployment and browser behavior.
Why this is a residual of CVE-2025-10354
- The CVE-2025-10354 hardening shipped by escaping the
qparameter before emitting it into thevalue="{{q}}"attribute. - Commit
3d675ceupdates only theqrendering to usehtmlspecialchars( $urlArgs->get( 'q', '' ) )and does not touch the adjacentcstate->$hiddenconstruction loop. - As a result,
cstateremains an unescaped input source that flows into the same raw template injection point ({{{hidden}}}), creating a distinct reflected-XSS lane.
Output (from code inspection)
Given the payload idea where cstate[0] starts with x" ... x", HtmlBuilder.php constructs the hidden fragment by concatenation:
<input name="cstate[0]" type="hidden" value="x" autofocus onfocus=alert(1) x">
Because search.mustache injects the fragment via {{{hidden}}}, the attacker-controlled markup participates in normal HTML parsing in the response body.
Suggested fix
- Escape both the
cstatekey and value when constructing$hidden. - Minimal code change in
src/MediaWiki/Specials/FacetedSearch/HtmlBuilder.php:
foreach ( $urlArgs->getArray( 'cstate' ) as $key => $value ) {
$safeKey = htmlspecialchars( (string)$key, ENT_QUOTES, 'UTF-8' );
$safeValue = htmlspecialchars( (string)$value, ENT_QUOTES, 'UTF-8' );
$hidden .= '<input name="cstate[' . $safeKey . ']" type="hidden" value="' . $safeValue . '">';
}
This keeps the raw {{{hidden}}} template insertion safe by ensuring the concatenated HTML fragment itself is attribute-escaped.
How I found it and a note on tooling
I anchored on the published CVE-2025-10354 patch by verifying in the checked-out repository that commit 3d675ce changes only the q rendering in HtmlBuilder.php to use htmlspecialchars.
Then I traced the reachable request path from SpecialFacetedSearch::execute() through ParametersProcessor::checkRequest() (checksum gate for whether cstate survives) into HtmlBuilder::buildHTML() where $hidden is constructed from cstate without escaping and injected into templates/FacetedSearch/search.mustache via {{{hidden}}}.
(End of file)
AI tooling
I used AI assistance for the code audit and for drafting this report. I manually verified the finding against the project's source at the location cited above before reporting it, and the severity and impact assessment are my own.
Technical details
Source: GitHub Advisory Database
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NMedium6.1Base score from GitHub Advisory Database
- Attack Vector AV
- Network
- Attack Complexity AC
- Low
- Privileges Required PR
- None
- User Interaction UI
- Required
- Scope S
- Changed
- Confidentiality C
- Low
- Integrity I
- Low
- Availability A
- None
Affected packages
Source: OSV (GitHub advisory)
- mediawiki/semantic-media-wikiPackagist (PHP)
pkg:composer/mediawiki/semantic-media-wiki- Affected versions
- >= 4.2.0, <= 7.2.0
- Fixed in
- 7.2.1
Show 10 listed versions
- 4.2.0
- 5.0.0
- 5.0.1
- 5.0.2
- 5.1.0
- 6.0.0
- 6.0.1
- 7.0.0
- 7.1.0
- 7.2.0
| Package | Affected versions | Fixed in |
|---|---|---|
mediawiki/semantic-media-wiki Packagist (PHP) pkg:composer/mediawiki/semantic-media-wiki |
Show 10 listed versions
|
|
Fix
Source: OSV (GitHub advisory)
Fix available
Upgrade to 7.2.1 or later.
Vulnerability intelligence
Root cause analysis
Vulnerable functions
References
Credits
- arpitjain099reporter
Questions about GHSA-9rcc-pmj8-ffhr
- Does GHSA-9rcc-pmj8-ffhr have a CVE ID?
- No CVE ID has been assigned to GHSA-9rcc-pmj8-ffhr yet. It is tracked only as a GitHub advisory.
- What is the CVSS score of GHSA-9rcc-pmj8-ffhr?
- GHSA-9rcc-pmj8-ffhr has a CVSS 3.1 base score of 6.1 (Medium), vector CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N.
- Which versions are affected by GHSA-9rcc-pmj8-ffhr?
- mediawiki/semantic-media-wiki (Packagist): >= 4.2.0, <= 7.2.0.
- How do I fix GHSA-9rcc-pmj8-ffhr?
- Upgrade to 7.2.1 or later.
- What is the Package URL (PURL) for GHSA-9rcc-pmj8-ffhr?
- The affected package's PURL is pkg:composer/mediawiki/semantic-media-wiki.
Data sources
Upstream records
Fetched 5 days ago (8 Oct 2026, 14:13 UTC). Records refresh automatically after 24 hours.
Where each part of this page came from
- Title and description
- OSV (GitHub advisory)
- Severity score
- GitHub Advisory Database
- Weakness (CWE)
- GitHub Advisory Database
- Affected packages
- OSV (GitHub advisory)
- Fix
- OSV (GitHub advisory)
- References
- Computed by CVEminer
OSV and GitHub Advisory Database content is licensed CC BY 4.0. Values marked as computed or derived were calculated by CVEminer from the upstream data.