{"id":"GHSA-9rcc-pmj8-ffhr","aliases":[],"url":"https://o3.security/vulnerability/GHSA-9rcc-pmj8-ffhr","summary":"Semantic MediaWiki's Special:FacetedSearch cstate hidden inputs enable reflected XSS (residual of CVE-2025-10354)","details":"### Summary\n\nSpecial:FacetedSearch `cstate` hidden inputs enable reflected XSS (residual of CVE-2025-10354)\n\n### Details\n\n#### Affected versions and vulnerable location\n\n- Confirmed present on latest shipped release tag available in the local clone: `SemanticMediaWiki/SemanticMediaWiki@7.2.0`.\n- Confirmed present on default branch `master` at HEAD `18f418b4cdf2875e67a741349179a22c1573f61c`.\n\nVulnerable sink (default-branch representation):\n\n- `src/MediaWiki/Specials/FacetedSearch/HtmlBuilder.php:131-133`\n  - Builds `$hidden` by concatenating unescaped request-controlled `cstate[$key]` values into an HTML attribute context (`value=\"...\"`).\n- `templates/FacetedSearch/search.mustache:25`\n  - Inserts the constructed fragment via `{{{hidden}}}` (no HTML escaping at this boundary).\n\n#### Reachability trace (verified from source)\n\n1. HTTP entrypoint:\n   - `GET` to `Special:FacetedSearch` dispatches into `SMW\\MediaWiki\\Specials\\SpecialFacetedSearch::execute()`.\n2. Request decoding boundary:\n   - `SpecialFacetedSearch::execute()` constructs `UrlArgs` from `$request->getValues()` and calls `ParametersProcessor::checkRequest($request)`.\n3. Checksum gate:\n   - `ParametersProcessor::checkRequest()` clears `cstate` only when `filtered != 1` and `getInt('csum', 0) != crc32(getVal('q', ''))`.\n4. Decoder -> HTML assembly:\n   - `HtmlBuilder::buildHTML()` iterates `foreach ( $urlArgs->getArray( 'cstate' ) as $key => $value )` and concatenates each into `$hidden` without escaping.\n   - `HtmlBuilder::buildHTML()` passes `$hidden` into the template variable `hidden`.\n5. HTML injection sink:\n   - `templates/FacetedSearch/search.mustache` renders `{{{hidden}}}` into the `<form>`, so the concatenated markup is inserted as raw HTML.\n\n### PoC\n\n#### Reproduction steps (source-derived)\n\n1. Choose a `q` value.\n2. Compute `csum` as `crc32(q)`.\n3. Send a request that includes:\n   - `q=<chosen>`\n   - `csum=<crc32(q)>`\n   - at least one `cstate[<key>]=<payload>` entry\n\nExample request shape:\n\n```text\n/index.php/Special:FacetedSearch?q=Text&csum=<crc32(Text)>&cstate[0]=x%22%20autofocus%20onfocus%3Dalert(1)%20x%22\n```\n\n### Impact\n\n#### Attacker model\n\n- Any remote attacker who can send HTTP requests to `Special:FacetedSearch` (or the localized alias mapped to the same `SpecialFacetedSearch` class) can supply attacker-controlled query parameters.\n- Preconditions:\n  - The attacker must make `cstate` survive `ParametersProcessor::checkRequest()`, either by setting `csum` to `crc32(q)` (when `filtered != 1`), or by setting `filtered=1`.\n  - The attacker must supply `cstate[<key>]` values containing characters that break out of the HTML `value=\"...\"` attribute context (for example an injected `\"` to terminate the attribute value).\n\n#### Severity and CVSS reasoning\n\nProposed severity: MEDIUM.\n\nProposed CVSS v3.1 vector: `CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N`.\n\nRationale:\n\n- AV:N: delivered over the network via query parameters.\n- AC:L: requires only setting `q`, `csum`, and at least one `cstate` entry.\n- PR:N: no authentication required for the request path in this code.\n- UI:R: the victim must load the crafted URL.\n- S:C: reflected XSS executes in the wiki origin and can affect other users depending on deployment and browser behavior.\n\n### Why this is a residual of CVE-2025-10354\n\n- The CVE-2025-10354 hardening shipped by escaping the `q` parameter before emitting it into the `value=\"{{q}}\"` attribute.\n- Commit `3d675ce` updates only the `q` rendering to use `htmlspecialchars( $urlArgs->get( 'q', '' ) )` and does not touch the adjacent `cstate` -> `$hidden` construction loop.\n- As a result, `cstate` remains an unescaped input source that flows into the same raw template injection point (`{{{hidden}}}`), creating a distinct reflected-XSS lane.\n\n### Output (from code inspection)\n\nGiven the payload idea where `cstate[0]` starts with `x\" ... x\"`, `HtmlBuilder.php` constructs the hidden fragment by concatenation:\n\n```html\n<input name=\"cstate[0]\" type=\"hidden\" value=\"x\" autofocus onfocus=alert(1) x\">\n```\n\nBecause `search.mustache` injects the fragment via `{{{hidden}}}`, the attacker-controlled markup participates in normal HTML parsing in the response body.\n\n### Suggested fix\n\n- Escape both the `cstate` key and value when constructing `$hidden`.\n- Minimal code change in `src/MediaWiki/Specials/FacetedSearch/HtmlBuilder.php`:\n\n```php\nforeach ( $urlArgs->getArray( 'cstate' ) as $key => $value ) {\n\t$safeKey = htmlspecialchars( (string)$key, ENT_QUOTES, 'UTF-8' );\n\t$safeValue = htmlspecialchars( (string)$value, ENT_QUOTES, 'UTF-8' );\n\t$hidden .= '<input name=\"cstate[' . $safeKey . ']\" type=\"hidden\" value=\"' . $safeValue . '\">';\n}\n```\n\nThis keeps the raw `{{{hidden}}}` template insertion safe by ensuring the concatenated HTML fragment itself is attribute-escaped.\n\n### How I found it and a note on tooling\n\nI 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`.\n\nThen 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}}}`.\n\n(End of file)\n\n### AI tooling\n\nI 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.","published":"2026-09-18T16:59:16Z","modified":"2026-09-18T17:15:05.090528756Z","cvss":{"score":6.1,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"},"epss":null,"cisaKev":null,"exploitsKnown":null,"affectedPackages":[{"ecosystem":"Packagist","name":"mediawiki/semantic-media-wiki","fixedVersion":"7.2.1"}],"fix":null,"references":[{"type":"WEB","url":"https://github.com/SemanticMediaWiki/SemanticMediaWiki/security/advisories/GHSA-9rcc-pmj8-ffhr"},{"type":"PACKAGE","url":"https://github.com/SemanticMediaWiki/SemanticMediaWiki"},{"type":"WEB","url":"https://github.com/SemanticMediaWiki/SemanticMediaWiki/releases/tag/7.2.1"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-09-18T17:15:05.090528756Z"}}