Soumettre #992820: Formwork Formwork CMS 2.3.12 Stored Cross-Site Scripting (CWE-79)information

TitreFormwork Formwork CMS 2.3.12 Stored Cross-Site Scripting (CWE-79)
Description# Private Security Report: Stored XSS via `formaction` URI Sanitizer Bypass ## Disclosure status - Product: Formwork CMS (`getformwork/formwork`) - Tested release: 2.3.12 - Tested current branch: `2.x` at `0dcecf2ce08b44971f75be379b0917897104ff56` - Status: Confirmed locally; not publicly disclosed - Suggested CWE: CWE-79 - Suggested severity: Medium - Suggested CVSS 3.1: `CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N` (5.4) ## Summary Formwork's HTML sanitizer allows the URL-valued `formaction` attribute but does not include it in the list of attributes subject to URI scheme validation. As a result, a `javascript:` URI survives sanitization unchanged. When `pages.content.allowHtml` is enabled, an authenticated content editor can store a crafted `<button formaction="javascript:...">` in a Markdown field. A visitor who activates the button executes attacker-controlled JavaScript in the Formwork site's origin. The system option is presented as "Allow HTML in Markdown fields" and states that potentially dangerous content is still converted to text. Formwork also unconditionally passes rendered Markdown through `HtmlSanitizer`, establishing the sanitizer as a security boundary even when HTML is enabled. ## Preconditions 1. An administrator enables `pages.content.allowHtml` through System Options. 2. The attacker has an authenticated role that can edit pages. The bundled `editor` role grants `panel.pages: true`. 3. A victim visits the affected page and clicks the attacker-controlled submit button. The option is disabled by default, which is reflected in the proposed Medium severity and user-interaction requirement. ## Root cause `formwork/src/Sanitizer/Reference/HtmlReference.php` contains `formaction` in `ALLOWED_ATTRIBUTES`, but `URI_ATTRIBUTES` contains only: ```php [ 'action', 'src', 'href', 'lowsrc', 'background', 'ping', ] ``` `formwork/src/Sanitizer/DomSanitizer.php::sanitizeNodeAttribute()` performs URI scheme validation only when the attribute is present in `URI_ATTRIBUTES`. Therefore, `formaction="javascript:..."` bypasses `allowedUriSchemes` and is serialized unchanged. Data flow: ```text Editor-controlled Markdown -> Markdown::parse(allowHtml: true) -> CommonMark HTML output -> HtmlSanitizer -> formaction is allowed but not URI-validated -> persistent page HTML -> victim clicks button -> JavaScript executes in site origin ``` ## Minimal sanitizer reproduction Run from the extracted Formwork 2.3.12 directory: ```bash php -r 'require "vendor/autoload.php"; $s=new Formwork\Sanitizer\HtmlSanitizer(); echo $s->sanitize("<form><button formaction=\"javascript:alert(document.domain)\">Click</button></form>");' ``` Observed output: ```html <form><button formaction="javascript:alert(document.domain)">Click</button></form> ``` The dangerous URI is preserved. The command above is a self-contained reproducer against an extracted Formwork 2.3.12 release. ## End-to-end reproduction 1. Install Formwork 2.3.12. 2. Enable **System Options -> Content -> Allow HTML in Markdown fields**. 3. As a user with page-editing permission, create a page containing: ```html <p id="result">NOT_EXECUTED</p> <form><button id="trigger" formaction="javascript:void(document.getElementById('result').textContent='FORMWORK_XSS_EXECUTED')">Trigger</button></form> ``` 4. Open the published page and click **Trigger**. Observed before the click: ```json { "result": "NOT_EXECUTED", "button": "javascript:void(document.getElementById('result').textContent='FORMWORK_XSS_EXECUTED')", "url": "http://127.0.0.1:8765/poc/" } ``` Observed after a real Chromium mouse click: ```json { "result": "FORMWORK_XSS_EXECUTED", "url": "http://127.0.0.1:8765/poc/", "origin": "http://127.0.0.1:8765" } ``` This confirms JavaScript execution in the Formwork origin, not merely preservation of a suspicious string. ## Impact An attacker with content-editing privileges can execute JavaScript in the browser of visitors who interact with the crafted control. Depending on the victim and deployment, this can allow actions in the victim's authenticated context, access to origin-readable data, content manipulation, phishing, or session compromise where credentials are accessible to JavaScript. ## Affected versions The same vulnerable allowlist and conditional URI validation are present in tag `2.0.0-beta.2`, release `2.3.12`, and the current `2.x` branch at commit `0dcecf2ce08b44971f75be379b0917897104ff56` (checked 2026-08-21). Proposed affected range: ```text >= 2.0.0-beta.2, <= 2.3.12 ``` The current development branch should also be considered affected until patched. ## Duplicate review The following were reviewed on 2026-08-21: - All 11 public repository security advisories returned by GitHub's repository advisory API. - NVD keyword results for Formwork: CVE-2023-24230, CVE-2024-35621, CVE-2024-37160, CVE-2025-65956, and CVE-2026-27198. - Web searches for Formwork combined with `formaction`, sanitizer bypass, and `javascript:` URI. - Current `2.x` source compared with release 2.3.12. No existing Formwork advisory or CVE describing this root cause or vector was found. Similar 2026 CVEs in other sanitizer products confirm the vulnerability class but concern independent codebases and are not duplicates of this product-specific issue. ## Suggested remediation At minimum, add `formaction` to `HtmlReference::URI_ATTRIBUTES`: ```php public const array URI_ATTRIBUTES = [ 'action', 'formaction', 'src', 'href', 'lowsrc', 'background', 'ping', ]; ``` The minimal fix was tested locally. The same payload is transformed into: ```html <form><button>Click</button></form> ``` Recommended follow-up hardening: - Audit every allowed attribute that can carry a URL or executable document. - Prefer element-and-attribute-aware validation rather than one global attribute list. - Remove or separately sanitize attributes such as `srcdoc` that contain markup rather than a normal URI. - Add regression tests for `formaction` on both `<button>` and `<input type="submit|image">`, including encoded and mixed-case `javascript:` values. ## Responsible disclosure route Submit privately through the repository's **Report a vulnerability** flow: https://github.com/getformwork/formwork/security/advisories/new The project's security policy states that confirmed vulnerabilities will be handled through GitHub and that the maintainers will request a CVE ID. Vendor coordination Existing GHSA-p78q-v3pr-p87j; reporter requested impact update and CVE handling from the maintainer. CVE assignment requested from VulDB; no CVE known at submission time.
La source⚠️ https://github.com/getformwork/formwork/security/advisories/GHSA-p78q-v3pr-p87j
Utilisateur
 fernando viana (UID 101484)
Soumission21/09/2026 02:17 (il y a 16 jours)
Modérer06/10/2026 10:04 (15 days later)
StatutAccepté
Entrée VulDB413925 [getformwork jusqu’à 2.3.12 URI Sanitizer DomSanitizer.php sanitizeNodeAttribute formaction cross site scripting]
Points20