GHSA-x3hr-cp7x-44r2: CI4MS has stored XSS via srcdoc attribute bypass in Google Maps iframe setting
SummaryThe Google Maps iframe setting (`cMap` field) in `compInfosPost()` sanitizes input using `strip_tags()` with an `<iframe>` allowlist and regex-based removal of `on\w+` event handlers. However, the `srcdoc` attribute is not an event handler and passes all filters. An attacker with admin settings access can inject an `<iframe srcdoc="...">` payload with HTML-entity-encoded JavaScript that executes in the context of the parent page when rendered to unauthenticated frontend visitors.Details**Input sanitization** (`modules/Settings/Controllers/Settings.php:49-53`):The three regex patterns only match attributes beginning with `on` (e.g., `onclick`, `onerror`). The `srcdoc` attribute does not begin with `on` and passes through untouched.**Output rendering** (`app/Views/templates/default/gmapiframe.php:3`):The output applies `strip_tags` with the same `<iframe>` allowlist but performs no attribute filtering or HTML encoding. The stored payload is rendered verbatim.**Why HTML entities bypass `strip_tags`**: A payload like `<iframe srcdoc="&lt;script&gt;alert(1)&lt;/script&gt;">` contains only one tag (`<iframe>`), which is in the allowlist. The entity-encoded content (`&lt;script&gt;`) is not recognized as a tag by `strip_tags`. However, when the browser renders the `srcdoc` attribute, it decodes the HTML entities and creates a new browsing context containing `<script>alert(1)</script>`.**Why this is same-origin**: Per the HTML specification, an `<iframe srcdoc="...">` without a `sandbox` attribute inherits the parent document's origin. The injected script has full access to the parent page's cookies, DOM, and session.PoC**Prerequisites**: Authenticated admin session with `update` role on the Settings module.**Step 1: Inject the payload**The `cMap` value decodes to:**Step 2: Visit any public page that includes the Google Maps widget**Navigate to the frontend contact or footer page as an unauthenticated visitor. The browser renders the `srcdoc` iframe, decodes the entities, and executes the script in the parent page's origin.**Expected result**: JavaScript `alert(document.domain)` fires showing the target's domain, confirming same-origin execution.**Cookie theft variant**:Impact**Stored XSS affecting all frontend visitors**: The payload persists in the settings database and executes for every unauthenticated visitor viewing pages that include the Google Maps iframe widget.**Session hijacking**: The script executes in the parent page's origin, giving access to session cookies (unless HttpOnly is set) and the full DOM.**Credential theft**: An attacker can inject a fake login form or redirect users to a phishing page.**Scope change**: The attack crosses from the admin backend trust boundary to the public frontend, affecting users who have no relationship with the backend.The attack requires a compromised or malicious admin account with settings update permission. While this is a privileged starting point (PR:H), the impact crosses to all unauthenticated visitors (S:C), justifying Medium severity.Recommended FixReplace the regex-based attribute blocklist with a strict allowlist approach. Only allow `src`, `width`, `height`, `frameborder`, `style`, `allowfullscreen`, and `loading` attributes on iframe tags:This allowlist approach ensures that dangerous attributes like `srcdoc`, `src` with `javascript:` protocol, and any future dangerous attributes are blocked by default.
CVSS v3.1: 5.5