VYPR
Moderate severityNVD Advisory· Published Feb 4, 2026· Updated Feb 5, 2026

HtmlSanitizer has a bypass via template tag

CVE-2026-25543

Description

HtmlSanitizer is a .NET library for cleaning HTML fragments and documents from constructs that can lead to XSS attacks. Prior to versions 9.0.892 and 9.1.893-beta, if the template tag is allowed, its contents are not sanitized. The template tag is a special tag that does not usually render its contents, unless the shadowrootmode attribute is set to open or closed. This issue has been patched in versions 9.0.892 and 9.1.893-beta.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

HtmlSanitizer for .NET fails to sanitize content inside allowed tags, enabling XSS when shadowrootmode is set.

Vulnerability

Overview

CVE-2026-25543 is a cross-site scripting (XSS) vulnerability in the HtmlSanitizer .NET library. The root cause is that when the ` tag is included in the allowed tags list, the library does not sanitize the contents of that tag. The element is a special HTML container that normally does not render its children, but when the shadowrootmode attribute is set to open or closed`, the browser creates a shadow root and renders the template's content, making any unsanitized markup executable [1][2].

Exploitation

An attacker can exploit this by injecting a ` tag with a shadowrootmode attribute and malicious HTML or JavaScript inside it. If the application uses HtmlSanitizer to process user-supplied HTML and has ` in its allowed tags, the sanitizer will pass the template's inner content through unchanged. When the resulting HTML is rendered in a browser, the shadow root is created and the attacker's payload is executed, bypassing the sanitizer's intended protection [2][3].

Impact

Successful exploitation allows an attacker to inject arbitrary JavaScript into the context of the application's origin, leading to full XSS attacks. This can result in session hijacking, data theft, defacement, or other malicious actions performed in the context of the victim user's session. The vulnerability affects all versions prior to the patched releases [2].

Mitigation

The issue has been fixed in HtmlSanitizer versions 9.0.892 and 9.1.893-beta. Users should upgrade to one of these versions immediately. If upgrading is not possible, administrators can temporarily mitigate the risk by removing the `` tag from the allowed tags list in the sanitizer configuration [2][3][4].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
HtmlSanitizerNuGet
< 9.0.8929.0.892
HtmlSanitizerNuGet
>= 9.1.878-beta, < 9.1.893-beta9.1.893-beta

Affected products

2

Patches

1
0ac53dca30dd

Sanitize contents of template tag

https://github.com/mganss/HtmlSanitizerMichael GanssFeb 2, 2026via ghsa
2 files changed · +27 4
  • src/HtmlSanitizer/HtmlSanitizer.cs+14 4 modified
    @@ -498,7 +498,7 @@ private static void DefaultEncodeLiteralTextElementContent(IElement tag)
                 tag.SetInnerText(escapedHtml);
         }
     
    -    private void DoSanitize(IHtmlDocument dom, IParentNode context, string baseUrl = "")
    +    private void DoSanitize(INode dom, IParentNode context, string baseUrl = "")
         {
             // remove disallowed tags
             foreach (var tag in context.QuerySelectorAll("*").Where(t => !IsAllowedTag(t)).ToList())
    @@ -520,6 +520,11 @@ private void DoSanitize(IHtmlDocument dom, IParentNode context, string baseUrl =
             // cleanup attributes
             foreach (var tag in context.QuerySelectorAll("*").ToList())
             {
    +            if (tag is IHtmlTemplateElement templateElement && templateElement.Content is IDocumentFragment fragment)
    +            {
    +                DoSanitize(fragment, fragment, baseUrl);
    +            }
    +
                 // remove disallowed attributes
                 foreach (var attribute in tag.Attributes.Where(a => !IsAllowedAttribute(a)).ToList())
                 {
    @@ -575,12 +580,17 @@ private void DoSanitize(IHtmlDocument dom, IParentNode context, string baseUrl =
                 RemoveComments(node);
             }
     
    -        DoPostProcess(dom, context as INode);
    +        var doc = dom as IHtmlDocument ?? dom.Owner as IHtmlDocument;
    +
    +        if (doc != null)
    +        {
    +            DoPostProcess(doc, context as INode);
    +        }
         }
     
    -    private void SanitizeStyleSheets(IHtmlDocument dom, string baseUrl)
    +    private void SanitizeStyleSheets(INode node, string baseUrl)
         {
    -        foreach (var styleSheet in dom.StyleSheets.OfType<ICssStyleSheet>())
    +        foreach (var styleSheet in node.GetStyleSheets().OfType<ICssStyleSheet>())
             {
                 var styleTag = styleSheet.OwnerNode;
                 var i = 0;
    
  • test/HtmlSanitizer.Tests/Tests.cs+13 0 modified
    @@ -3629,4 +3629,17 @@ public void DisallowStyleTagCssCustomPropertiesTest()
             var sanitized = sanitizer.Sanitize(input);
             Assert.Equal("<style>:root { }</style>", sanitized);
         }
    +
    +    [Fact]
    +    public void TemplateTest()
    +    {
    +        var sanitizer = new HtmlSanitizer();
    +        sanitizer.AllowedTags.Add("template");
    +        sanitizer.AllowedTags.Add("style");
    +
    +        var html = "<div><template><style>div { display: none }</style><script>alert('xss')</script></template></div>";
    +        var sanitized = sanitizer.Sanitize(html);
    +        var expected = "<div><template><style>div { display: none }</style></template></div>";
    +        Assert.Equal(expected, sanitized);
    +    }
     }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.