{"id":"CVE-2026-41886","aliases":["EUVD-2026-28796","GHSA-w937-fg2h-xhq2"],"status":"published","title":"locize Client SDK: Cross-origin DOM XSS \u0026 Handler Hijack Through Missing e.origin Validation in InContext Editor","description":"locize is a localization platform that connects code and i18n setup. Prior to version 4.0.21, the locize client SDK registers a window.addEventListener(\"message\", …) handler that dispatches to registered internal handlers (editKey, commitKey, commitKeys, isLocizeEnabled, requestInitialize, …) without validating event.origin. The pre-patch listener in src/api/postMessage.js gates dispatch on event.data.sender === \"i18next-editor-frame\" — that value sits inside the attacker-controlled message payload, not the browser-enforced origin. Any web page that could embed or be embedded by a locize-enabled host — an iframe on a third-party page, a window.open-ed victim, a parent frame reaching down — could send a crafted postMessage and trigger the internal handlers. This issue has been patched in version 4.0.21.","severity":{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00101,"percentile":0.00904,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-346","CWE-79"],"published":"2026-04-22T20:32:11Z","modified":"2026-10-28T02:31:00Z","fixes":[{"ecosystem":"npm","package":"locize","fixed_in":["4.0.21"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"locize","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.0.21"}]}]},{"source":"osv","ecosystem":"npm","package":"locize","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"4.0.21"}]}]}],"products":[{"vendor":"locize","product":"locize"}],"references":[{"url":"https://github.com/locize/locize/security/advisories/GHSA-w937-fg2h-xhq2","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/locize/locize/releases/tag/v4.0.21","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/locize/locize/commit/d006b75fadb8e8ab77b023e462850fc6e9170735","tags":["web"]},{"url":"https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#security_concerns","tags":["web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41886","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-w937-fg2h-xhq2"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/41xxx/CVE-2026-41886.json","tags":["advisory"]},{"url":"https://github.com/locize/locize","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-41886","title":"locize Client SDK: Cross-origin DOM XSS \u0026 Handler Hijack Through Missing e.origin Validation in InContext Editor","description":"locize is a localization platform that connects code and i18n setup. Prior to version 4.0.21, the locize client SDK registers a window.addEventListener(\"message\", …) handler that dispatches to registered internal handlers (editKey, commitKey, commitKeys, isLocizeEnabled, requestInitialize, …) without validating event.origin. The pre-patch listener in src/api/postMessage.js gates dispatch on event.data.sender === \"i18next-editor-frame\" — that value sits inside the attacker-controlled message payload, not the browser-enforced origin. Any web page that could embed or be embedded by a locize-enabled host — an iframe on a third-party page, a window.open-ed victim, a parent frame reaching down — could send a crafted postMessage and trigger the internal handlers. This issue has been patched in version 4.0.21.","status":"published","published":"2026-05-08T15:45:23.262Z","modified":"2026-05-08T21:26:51.755Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L","level":"high","assessor":"cna"}],"cwes":["CWE-79","CWE-346"],"updated_at":"2026-11-02T13:41:08.498858Z"}],"euvd":[{"id":"EUVD-2026-28796","description":"locize is a localization platform that connects code and i18n setup. Prior to version 4.0.21, the locize client SDK registers a window.addEventListener(\"message\", …) handler that dispatches to registered internal handlers (editKey, commitKey, commitKeys, isLocizeEnabled, requestInitialize, …) without validating event.origin. The pre-patch listener in src/api/postMessage.js gates dispatch on event.data.sender === \"i18next-editor-frame\" — that value sits inside the attacker-controlled message payload, not the browser-enforced origin. Any web page that could embed or be embedded by a locize-enabled host — an iframe on a third-party page, a window.open-ed victim, a parent frame reaching down — could send a crafted postMessage and trigger the internal handlers. This issue has been patched in version 4.0.21.","status":"published","published":"2026-05-08T15:45:23Z","modified":"2026-05-08T21:26:51Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L","level":"high"}],"updated_at":"2026-11-02T19:05:14.089367Z"}],"ghsa":[{"id":"GHSA-w937-fg2h-xhq2","title":"locize Client SDK: Cross-origin DOM XSS \u0026 Handler Hijack Through Missing e.origin Validation in InContext Editor ","description":"### Summary\n\nVersions of the `locize` client SDK (the browser module that wires up the locize InContext translation editor) prior to 4.0.21 register a `window.addEventListener(\"message\", …)` handler that dispatches to registered internal handlers (`editKey`, `commitKey`, `commitKeys`, `isLocizeEnabled`, `requestInitialize`, …) **without validating `event.origin`**.\n\nThe pre-patch listener in `src/api/postMessage.js` gates dispatch on `event.data.sender === \"i18next-editor-frame\"` — that value sits inside the attacker-controlled message payload, not the browser-enforced origin. Any web page that could embed or be embedded by a locize-enabled host — an iframe on a third-party page, a `window.open`-ed victim, a parent frame reaching down — could send a crafted `postMessage` and trigger the internal handlers.\n\n### Impact\n\nDepending on which handler the attacker invokes, distinct consequences follow. All of them share the same root cause: the handlers implicitly assumed the payload came from the real editor iframe.\n\n- **Cross-origin DOM XSS** via `editKey` / `commitKeys`: the pre-patch `handleEditKey` assigned attacker-controlled payload values to `item.node.innerHTML` and to `item.node.setAttribute(attr, value)`. That allowed planting `\u003cscript\u003e`, `\u003cimg onerror\u003e`, or `onclick`/`onload`/`onfocus` event handlers; and on attribute writes, `href=\"javascript:…\"` / `src=\"data:text/html,\u003cscript\u003e…\"` / `style=\"…\"` / etc.\n\n- **`api.source` / `api.origin` hijack** via `isLocizeEnabled`: the handler set `api.source = e.source; api.origin = e.origin` — attacker-controlled values. All subsequent `sendMessage` calls (which post translations, callbacks, etc., back toward `api.source`) would go to the attacker window rather than the real editor, leaking translation content and any metadata the SDK forwards.\n\n- **CSS-injection / layout-escape** via `requestPopupChanges`: `containerStyle.height` / `.width` were interpolated into `calc()` expressions and `popup.style.setProperty()` without validation, allowing attackers to inject additional CSS declarations (semicolons, `behavior:url()` on legacy IE, CSS-exfil patterns) into the popup inline style.\n\nExploitation requires the attacker-owned page to share a window reference with the locize-enabled host: typical vectors are an `iframe` on an attacker-controlled page, a `window.opener`/`window.open` relationship, or a parent frame that can `postMessage` into an embedded locize host. The SDK intended model is that only the editor iframe at `https://incontext.locize.app` (or the configured staging/development origin) can reach these handlers.\n\n### Affected versions\n\nAll versions of `locize` prior to **4.0.21**.\n\n### Patch\n\nFixed in **4.0.21**. Two layers:\n\n1. **Primary** — validate `event.origin` at the top of `window.addEventListener(\"message\", …)` in `src/api/postMessage.js`. The expected origin is the configured iframe origin (`getIframeUrl()`), so custom environments continue to work. Messages from any other origin are silently dropped before any handler runs.\n\n2. **Defence-in-depth** — `handleEditKey` now rejects dangerous attribute-name writes (`on*`, `style`) and `javascript:` / `data:` / `vbscript:` / `file:` URLs on `href` / `src` / `action` / `formaction` / `xlink:href`; `innerHTML` assignments are sanitised through a throwaway DOMParser document (stripping `\u003cscript\u003e`, `\u003ciframe\u003e`, `\u003cobject\u003e`, `\u003cembed\u003e`, `\u003clink\u003e`, `\u003cmeta\u003e`, `\u003cbase\u003e`, `\u003cstyle\u003e` plus event handlers and dangerous URL schemes). Legitimate translation formatting (`\u003cb\u003e`, `\u003cem\u003e`, `\u003cstrong\u003e`, `\u003ca href=\"https://…\"\u003e`, etc.) passes through.\n\n3. **CSS-injection** — `handleRequestPopupChanges` now requires `containerStyle.height` / `.width` to match a strict CSS length pattern; malformed values are dropped silently.\n\n### Workarounds\n\nNo workaround short of upgrading.\n\n### Credits\n\nDiscovered via an internal security audit of the locize ecosystem.","status":"published","published":"2026-04-22T20:32:11Z","modified":"2026-05-13T13:30:13Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L","level":"high"}],"cwes":["CWE-79","CWE-346"],"updated_at":"2026-11-02T14:40:07.01746Z"}],"nvd":[{"id":"CVE-2026-41886","description":"locize is a localization platform that connects code and i18n setup. Prior to version 4.0.21, the locize client SDK registers a window.addEventListener(\"message\", …) handler that dispatches to registered internal handlers (editKey, commitKey, commitKeys, isLocizeEnabled, requestInitialize, …) without validating event.origin. The pre-patch listener in src/api/postMessage.js gates dispatch on event.data.sender === \"i18next-editor-frame\" — that value sits inside the attacker-controlled message payload, not the browser-enforced origin. Any web page that could embed or be embedded by a locize-enabled host — an iframe on a third-party page, a window.open-ed victim, a parent frame reaching down — could send a crafted postMessage and trigger the internal handlers. This issue has been patched in version 4.0.21.","status":"published","published":"2026-05-08T16:16:12.06Z","modified":"2026-06-17T10:47:08.593Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L","level":"high","assessor":"secondary"}],"cwes":["CWE-79","CWE-346"],"updated_at":"2026-11-02T14:12:17.842772Z"}],"osv":[{"id":"CVE-2026-41886","title":"locize Client SDK: Cross-origin DOM XSS \u0026 Handler Hijack Through Missing e.origin Validation in InContext Editor","description":"locize is a localization platform that connects code and i18n setup. Prior to version 4.0.21, the locize client SDK registers a window.addEventListener(\"message\", …) handler that dispatches to registered internal handlers (editKey, commitKey, commitKeys, isLocizeEnabled, requestInitialize, …) without validating event.origin. The pre-patch listener in src/api/postMessage.js gates dispatch on event.data.sender === \"i18next-editor-frame\" — that value sits inside the attacker-controlled message payload, not the browser-enforced origin. Any web page that could embed or be embedded by a locize-enabled host — an iframe on a third-party page, a window.open-ed victim, a parent frame reaching down — could send a crafted postMessage and trigger the internal handlers. This issue has been patched in version 4.0.21.","status":"published","published":"2026-05-08T15:45:23.262Z","modified":"2026-10-28T02:31:00.935525462Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L","level":"high"}],"cwes":["CWE-346","CWE-79"],"updated_at":"2026-11-02T15:45:03.764807Z"},{"id":"GHSA-w937-fg2h-xhq2","title":"locize Client SDK: Cross-origin DOM XSS \u0026 Handler Hijack Through Missing e.origin Validation in InContext Editor ","description":"### Summary\n\nVersions of the `locize` client SDK (the browser module that wires up the locize InContext translation editor) prior to 4.0.21 register a `window.addEventListener(\"message\", …)` handler that dispatches to registered internal handlers (`editKey`, `commitKey`, `commitKeys`, `isLocizeEnabled`, `requestInitialize`, …) **without validating `event.origin`**.\n\nThe pre-patch listener in `src/api/postMessage.js` gates dispatch on `event.data.sender === \"i18next-editor-frame\"` — that value sits inside the attacker-controlled message payload, not the browser-enforced origin. Any web page that could embed or be embedded by a locize-enabled host — an iframe on a third-party page, a `window.open`-ed victim, a parent frame reaching down — could send a crafted `postMessage` and trigger the internal handlers.\n\n### Impact\n\nDepending on which handler the attacker invokes, distinct consequences follow. All of them share the same root cause: the handlers implicitly assumed the payload came from the real editor iframe.\n\n- **Cross-origin DOM XSS** via `editKey` / `commitKeys`: the pre-patch `handleEditKey` assigned attacker-controlled payload values to `item.node.innerHTML` and to `item.node.setAttribute(attr, value)`. That allowed planting `\u003cscript\u003e`, `\u003cimg onerror\u003e`, or `onclick`/`onload`/`onfocus` event handlers; and on attribute writes, `href=\"javascript:…\"` / `src=\"data:text/html,\u003cscript\u003e…\"` / `style=\"…\"` / etc.\n\n- **`api.source` / `api.origin` hijack** via `isLocizeEnabled`: the handler set `api.source = e.source; api.origin = e.origin` — attacker-controlled values. All subsequent `sendMessage` calls (which post translations, callbacks, etc., back toward `api.source`) would go to the attacker window rather than the real editor, leaking translation content and any metadata the SDK forwards.\n\n- **CSS-injection / layout-escape** via `requestPopupChanges`: `containerStyle.height` / `.width` were interpolated into `calc()` expressions and `popup.style.setProperty()` without validation, allowing attackers to inject additional CSS declarations (semicolons, `behavior:url()` on legacy IE, CSS-exfil patterns) into the popup inline style.\n\nExploitation requires the attacker-owned page to share a window reference with the locize-enabled host: typical vectors are an `iframe` on an attacker-controlled page, a `window.opener`/`window.open` relationship, or a parent frame that can `postMessage` into an embedded locize host. The SDK intended model is that only the editor iframe at `https://incontext.locize.app` (or the configured staging/development origin) can reach these handlers.\n\n### Affected versions\n\nAll versions of `locize` prior to **4.0.21**.\n\n### Patch\n\nFixed in **4.0.21**. Two layers:\n\n1. **Primary** — validate `event.origin` at the top of `window.addEventListener(\"message\", …)` in `src/api/postMessage.js`. The expected origin is the configured iframe origin (`getIframeUrl()`), so custom environments continue to work. Messages from any other origin are silently dropped before any handler runs.\n\n2. **Defence-in-depth** — `handleEditKey` now rejects dangerous attribute-name writes (`on*`, `style`) and `javascript:` / `data:` / `vbscript:` / `file:` URLs on `href` / `src` / `action` / `formaction` / `xlink:href`; `innerHTML` assignments are sanitised through a throwaway DOMParser document (stripping `\u003cscript\u003e`, `\u003ciframe\u003e`, `\u003cobject\u003e`, `\u003cembed\u003e`, `\u003clink\u003e`, `\u003cmeta\u003e`, `\u003cbase\u003e`, `\u003cstyle\u003e` plus event handlers and dangerous URL schemes). Legitimate translation formatting (`\u003cb\u003e`, `\u003cem\u003e`, `\u003cstrong\u003e`, `\u003ca href=\"https://…\"\u003e`, etc.) passes through.\n\n3. **CSS-injection** — `handleRequestPopupChanges` now requires `containerStyle.height` / `.width` to match a strict CSS length pattern; malformed values are dropped silently.\n\n### Workarounds\n\nNo workaround short of upgrading.\n\n### Credits\n\nDiscovered via an internal security audit of the locize ecosystem.","status":"published","published":"2026-04-22T20:32:11Z","modified":"2026-05-13T13:54:34.252474Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L","level":"high"}],"cwes":["CWE-346","CWE-79"],"updated_at":"2026-11-02T15:46:58.401149Z"}]}}
