PDFME has XSS via Unsanitized i18n Label Injection into innerHTML in multiVariableText propPanel
Date: 2026-03
Affected: npm/@pdfme/schemas
Attack vector: xss
Category: vulnerability-disclosure
Severity: Medium
CWE: CWE-79
CVSS: 4.4 (CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:C/C:L/I:L/A:N)

## Summary The multiVariableText property panel in `@pdfme/schemas` constructs HTML via string concatenation and assigns it to `innerHTML` using unsanitized i18n label values. An attacker who can control label overrides passed through `options.labels` can inject arbitrary JavaScript that executes in the context of any user who opens the Designer and selects a multiVariableText field with no `{variables}` in its text. ## Details When a user selects a multiVariableText schema field that contains no `{variable}` placeholders, the property panel renders instructional text by concatenating i18n-translated strings directly into `innerHTML`. **Vulnerable sink** — `packages/schemas/src/multiVariableText/propPanel.ts:65-71`: ```typescript // Use safe string concatenation for innerHTML const typingInstructions = i18n('schemas.mvt.typingInstructions'); const sampleField = i18n('schemas.mvt.sampleField'); para.innerHTML = typingInstructions + ` <code style="color:${safeColorValue}; font-weight:bold;">{` + sampleField + '}</code>'; ``` The comment on line 64 claims "safe string concatenation" but the result is assigned to `innerHTML` with no HTML escaping applied to `typingInstructions` or `sampleField`. **i18n lookup has no escaping** — `packages/ui/src/i18n.ts:903`: ```typescript export const i18n = (key: keyof Dict, dict?: Dict) => (dict || getDict(DEFAULT_LANG))[key]; ``` This is a plain dictionary lookup — no HTML encoding or sanitization. **Label override via deep


Mitigations:

Architectural layers (MAESTRO):