CVE-2026-113787
odf-kit: HTML injection leading to XSS in odtToHtml() via unescaped style attribute values
odf-kit allows users to generate, fill, read, and convert OpenDocument Format files (.odt, .ods) in TypeScript and JavaScript. Starting in version 0.6.0 and prior to version 0.14.2, he renderer has an escapeHtml() helper and applies it consistently to text content and to attribute values — href, src, alt, id, data-author, data-date, citation text all go through it. The inline CSS strings do not. In renderTextSpan (dist/odt/to-html/html-renderer.js:195), the value of e.g. fo:color is copied from the document into style.fontColor verbatim by the parser (extractSpanStyle, read/parser.js:348), then concatenated raw into the attribute. A " in the value terminates the attribute early. The same unescaped style="${...}" pattern appears at roughly ten other emission sites: paragraph and heading (paragraphStyleToCss), table cells and rows (cellStyleToCss, rowStyleToCss), <col>, and the image style attribute. The affected source attributes include fo:color, fo:background-color, fo:text-shadow, fo:letter-spacing, fo:font-family (via both direct and font-face resolution), fo:margin-*, fo:padding-*, fo:line-height, fo:border*, and style:vertical-align. Version 0.14.2 contains a patch.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Required
What an attacker can affect
- Confidentiality
- Low
- Integrity
- Low
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.1
odf-kit: HTML injection leading to XSS in odtToHtml() via unescaped style attribute values
odf-kit allows users to generate, fill, read, and convert OpenDocument Format files (.odt, .ods) in TypeScript and JavaScript. Starting in version 0.6.0 and prior to version 0.14.2, he renderer has an escapeHtml() helper and applies it consistently to text content and to attribute values — href, src, alt, id, data-author, data-date, citation text all go through it. The inline CSS strings do not. In renderTextSpan (dist/odt/to-html/html-renderer.js:195), the value of e.g. fo:color is copied from the document into style.fontColor verbatim by the parser (extractSpanStyle, read/parser.js:348), then concatenated raw into the attribute. A " in the value terminates the attribute early. The same unescaped style="${...}" pattern appears at roughly ten other emission sites: paragraph and heading (paragraphStyleToCss), table cells and rows (cellStyleToCss, rowStyleToCss), <col>, and the image style attribute. The affected source attributes include fo:color, fo:background-color, fo:text-shadow, fo:letter-spacing, fo:font-family (via both direct and font-face resolution), fo:margin-*, fo:padding-*, fo:line-height, fo:border*, and style:vertical-align. Version 0.14.2 contains a patch.
- Record
CVE-2026-113787- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
EUVDEUVD-2026-107324
6.1
odf-kit: HTML injection leading to XSS in odtToHtml() and odsToHtml() via unescaped style attribute values
- Record
EUVD-2026-107324- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Updated
- 2026-11-04
GitHub AdvisoriesGHSA-3cgg-c5pp-57h6
6.1
odf-kit: HTML injection leading to XSS in odtToHtml() and odsToHtml() via unescaped style attribute values
Summary
ODF style attribute values are interpolated into style="..." attributes without HTML-escaping in both of odf-kit's to-HTML renderers (odtToHtml and odsToHtml). A double-quote character inside an attacker-controlled style value breaks out of the attribute, allowing arbitrary HTML/attribute injection — and therefore script execution (XSS) — from a crafted .odt or .ods file wherever the rendered output is inserted as HTML, which is the documented purpose of both functions.
Details
ODT renderer (src/odt/to-html/html-renderer.ts)
The renderer has an escapeHtml() helper and applies it consistently to text content and to attribute values — href, src, alt, id, data-author, data-date, citation text all go through it. The inline CSS strings do not.
In renderTextSpan (dist/odt/to-html/html-renderer.js:195):
const css = spanStyleToCss(span.style);
if (css)
html = `<span style="${css}">${html}</span>`;
The value of e.g. fo:color is copied from the document into style.fontColor verbatim by the parser (extractSpanStyle, read/parser.js:348), then concatenated raw into the attribute. A " in the value terminates the attribute early.
The same unescaped style="${...}" pattern appears at roughly ten other emission sites: paragraph and heading (paragraphStyleToCss), table cells and rows (cellStyleToCss, rowStyleToCss), <col>, and the image style attribute. The affected source attributes include fo:color, fo:background-color, fo:text-shadow, fo:letter-spacing, fo:font-family (via both direct and font-face resolution), fo:margin-*, fo:padding-*, fo:line-height, fo:border*, and style:vertical-align.
ODS renderer (src/ods/to-html/html-renderer.ts) — same bug
buildInlineStyle() assembles the CSS string from cell formatting properties — fo:color, fo:font-size, fo:font-family, fo:background-color, fo:text-align, etc. — with zero escapeHtml calls, and renderCell emits it raw (line 65):
if (includeStyles && cell.formatting) {
const style = buildInlineStyle(cell.formatting);
if (style) attrs.push(`style="${style}"`);
}
Additionally, row.height (from style:row-height) goes raw into the row element (line 95):
const style = includeStyles && row.height ? ` style="height:${row.height}"` : "";
return `<tr class="${prefix}-row"${style}>${cells}</tr>`;
The same injection is reachable through the public odf-kit/ods/to-html export (odsToHtml()), so both to-HTML directions are affected.
Version scope
The odt/to-html and ods/to-html modules first shipped in 0.14.0; the current latest release is 0.14.1. The PoCs were re-ran against the unreleased main branch (commit 270a361) — both injections still fire, so no fix has landed past the release.
PoC
Each PoC is a minimal ODF package (mimetype + META-INF/manifest.xml + content.xml) whose content.xml contains exactly one poisoned automatic style. The files are generated by this short Python script (stdlib only, no dependencies) — save as build-pocs.py and run python3 build-pocs.py:
import zipfile
def build(path, mimetype, content):
# ODF requires 'mimetype' first and stored uncompressed
with zipfile.ZipFile(path, "w") as z:
z.writestr(zipfile.ZipInfo("mimetype"), mimetype, compress_type=zipfile.ZIP_STORED)
z.writestr("META-INF/manifest.xml",
'<?xml version="1.0" encoding="UTF-8"?>\n'
'<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n'
' <manifest:file-entry manifest:full-path="/" manifest:media-type="' + mimetype + '"/>\n'
' <manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml"/>\n'
'</manifest:manifest>\n')
z.writestr("content.xml", content)
ODT = "application/vnd.oasis.opendocument.text"
ODS =…
- Record
GHSA-3cgg-c5pp-57h6- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-04
NVD
6.1
odf-kit allows users to generate, fill, read, and convert OpenDocument Format files (.odt, .ods) in TypeScript and JavaScript. Starting in version 0.6.0 and prior to version 0.14.2, he renderer has an escapeHtml() helper and applies it consistently to text content and to attribute values — href, src, alt, id, data-author, data-date, citation text all go through it. The inline CSS strings do not. In renderTextSpan (dist/odt/to-html/html-renderer.js:195), the value of e.g. fo:color is copied from the document into style.fontColor verbatim by the parser (extractSpanStyle, read/parser.js:348), then concatenated raw into the attribute. A " in the value terminates the attribute early. The same unescaped style="${...}" pattern appears at roughly ten other emission sites: paragraph and heading (paragraphStyleToCss), table cells and rows (cellStyleToCss, rowStyleToCss), <col>, and the image style attribute. The affected source attributes include fo:color, fo:background-color, fo:text-shadow, fo:letter-spacing, fo:font-family (via both direct and font-face resolution), fo:margin-*, fo:padding-*, fo:line-height, fo:border*, and style:vertical-align. Version 0.14.2 contains a patch.
- Record
CVE-2026-113787- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
OSV
6.1
odf-kit: HTML injection leading to XSS in odtToHtml() via unescaped style attribute values
odf-kit allows users to generate, fill, read, and convert OpenDocument Format files (.odt, .ods) in TypeScript and JavaScript. Starting in version 0.6.0 and prior to version 0.14.2, he renderer has an escapeHtml() helper and applies it consistently to text content and to attribute values — href, src, alt, id, data-author, data-date, citation text all go through it. The inline CSS strings do not. In renderTextSpan (dist/odt/to-html/html-renderer.js:195), the value of e.g. fo:color is copied from the document into style.fontColor verbatim by the parser (extractSpanStyle, read/parser.js:348), then concatenated raw into the attribute. A " in the value terminates the attribute early. The same unescaped style="${...}" pattern appears at roughly ten other emission sites: paragraph and heading (paragraphStyleToCss), table cells and rows (cellStyleToCss, rowStyleToCss), <col>, and the image style attribute. The affected source attributes include fo:color, fo:background-color, fo:text-shadow, fo:letter-spacing, fo:font-family (via both direct and font-face resolution), fo:margin-*, fo:padding-*, fo:line-height, fo:border*, and style:vertical-align. Version 0.14.2 contains a patch.
- Record
CVE-2026-113787- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
OSVGHSA-3cgg-c5pp-57h6
6.1
odf-kit: HTML injection leading to XSS in odtToHtml() and odsToHtml() via unescaped style attribute values
Summary
ODF style attribute values are interpolated into style="..." attributes without HTML-escaping in both of odf-kit's to-HTML renderers (odtToHtml and odsToHtml). A double-quote character inside an attacker-controlled style value breaks out of the attribute, allowing arbitrary HTML/attribute injection — and therefore script execution (XSS) — from a crafted .odt or .ods file wherever the rendered output is inserted as HTML, which is the documented purpose of both functions.
Details
ODT renderer (src/odt/to-html/html-renderer.ts)
The renderer has an escapeHtml() helper and applies it consistently to text content and to attribute values — href, src, alt, id, data-author, data-date, citation text all go through it. The inline CSS strings do not.
In renderTextSpan (dist/odt/to-html/html-renderer.js:195):
const css = spanStyleToCss(span.style);
if (css)
html = `<span style="${css}">${html}</span>`;
The value of e.g. fo:color is copied from the document into style.fontColor verbatim by the parser (extractSpanStyle, read/parser.js:348), then concatenated raw into the attribute. A " in the value terminates the attribute early.
The same unescaped style="${...}" pattern appears at roughly ten other emission sites: paragraph and heading (paragraphStyleToCss), table cells and rows (cellStyleToCss, rowStyleToCss), <col>, and the image style attribute. The affected source attributes include fo:color, fo:background-color, fo:text-shadow, fo:letter-spacing, fo:font-family (via both direct and font-face resolution), fo:margin-*, fo:padding-*, fo:line-height, fo:border*, and style:vertical-align.
ODS renderer (src/ods/to-html/html-renderer.ts) — same bug
buildInlineStyle() assembles the CSS string from cell formatting properties — fo:color, fo:font-size, fo:font-family, fo:background-color, fo:text-align, etc. — with zero escapeHtml calls, and renderCell emits it raw (line 65):
if (includeStyles && cell.formatting) {
const style = buildInlineStyle(cell.formatting);
if (style) attrs.push(`style="${style}"`);
}
Additionally, row.height (from style:row-height) goes raw into the row element (line 95):
const style = includeStyles && row.height ? ` style="height:${row.height}"` : "";
return `<tr class="${prefix}-row"${style}>${cells}</tr>`;
The same injection is reachable through the public odf-kit/ods/to-html export (odsToHtml()), so both to-HTML directions are affected.
Version scope
The odt/to-html and ods/to-html modules first shipped in 0.14.0; the current latest release is 0.14.1. The PoCs were re-ran against the unreleased main branch (commit 270a361) — both injections still fire, so no fix has landed past the release.
PoC
Each PoC is a minimal ODF package (mimetype + META-INF/manifest.xml + content.xml) whose content.xml contains exactly one poisoned automatic style. The files are generated by this short Python script (stdlib only, no dependencies) — save as build-pocs.py and run python3 build-pocs.py:
import zipfile
def build(path, mimetype, content):
# ODF requires 'mimetype' first and stored uncompressed
with zipfile.ZipFile(path, "w") as z:
z.writestr(zipfile.ZipInfo("mimetype"), mimetype, compress_type=zipfile.ZIP_STORED)
z.writestr("META-INF/manifest.xml",
'<?xml version="1.0" encoding="UTF-8"?>\n'
'<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n'
' <manifest:file-entry manifest:full-path="/" manifest:media-type="' + mimetype + '"/>\n'
' <manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml"/>\n'
'</manifest:manifest>\n')
z.writestr("content.xml", content)
ODT = "application/vnd.oasis.opendocument.text"
ODS =…
- Record
GHSA-3cgg-c5pp-57h6- CVSS 3.1
- 6.1 Medium
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-04
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
odf-kitnpm |
0.6.0 up to 0.14.2 | 0.14.2 |
History
| Recorded | Changed | Sources |
|---|---|---|
| published | EUVD | |
| affected, references | OSV | |
| affected, facts, references | GitHub Advisories | |
| first indexed | CVE List, EUVD, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-113787 is a medium vulnerability (CVSS 6.1) in Githubnewbie0 Odf-kit, published October 21, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.25%, the 16th percentile. Fixed in odf-kit 0.14.2.
References
github.com/GitHubNewbie0/odf-kit/security/advisories/GHSA-3cgg-c5pp-57h6
github.com/GitHubNewbie0/odf-kit/commit/fa3abc5a7a757f56c7212b2dbe99d1d2db995420
nvd.nist.gov/vuln/detail/CVE-2026-113787
github.com/GitHubNewbie0/odf-kit/releases/tag/v0.14.2
github.com/advisories/GHSA-3cgg-c5pp-57h6
github.com/CVEProject/cvelistV5/tree/main/cves/2026/113xxx/CVE-2026-113787.json
github.com/GitHubNewbie0/odf-kit
Left out here: the rest of 2 source descriptions. The JSON record has them.