Executive Summary

I read the Go Security team's announcement, forwarded to oss-security, about two CVEs in golang.org/x/net/html: one about a parser that can be made quadratically slow, and one about a parser that can mis-guess the namespace when re-rendering HTML. Both are bugs at the internal parser level, not in the public API we often call directly, but the impact hits anyone who parses untrusted HTML with this package.

Issues Addressed

The first, CVE-2026-78661, is in the addText and fosterParent functions. When the parser merges adjacent text nodes, the code uses the n.Data += text pattern — every time there's a new text token, Go has to reallocate and copy the entire string accumulated so far. That's a classic pattern that ends up O(n²): if the input has many short chunks of text separated by a closing tag the parser ignores (the example mentioned in the report: a tag like </a> that's invalid at that position), the number of allocations and byte copies explodes quadratically relative to the input size. From a security standpoint this is a pretty nasty DoS vector because the payload can be small but makes CPU/memory parsing cost spike far beyond linear. Found by Markus Magnuson, tracked as Go issue 82224.

The second, CVE-2026-97045, is in childTextNodesAreLiteral, the function that determines whether text content inside a foreign-namespace element (e.g. SVG/MathML) should be treated as raw text literal when rendered. Before the patch, this function walked up the ancestor chain but stopped as soon as it found the nearest HTML integration point. The problem is that the integration point itself could be an element that was foster-parented into another foreign namespace. As a result, if the parsing output is re-rendered into an HTML string and re-parsed (for example by a browser), the subtree could be interpreted as being in a different namespace than the one the original parser intended. This isn't just a matter of wrong output — it's a class of parser-differential bug that, if exploited, could open a path for content that was originally considered safe text to turn into active markup after re-parsing. Reported by Ali Sherif, tracked as Go issue 82622.

Key Features and Code Examples

For CVE-2026-78661, the fix changes the accumulation strategy: instead of repeated string concatenation, bytes are now accumulated into a per-node buffer first, and only turned into a string once at the end of parsing. Here's an illustration of the before/after pattern (this is my own example, not a quote from the official diff, since the full diff wasn't published in this announcement):

// Sebelum (ilustrasi) — setiap panggilan realokasi & copy seluruh string
n.Data += text // O(n) per token, O(n^2) total untuk banyak token pendek

// Sesudah (ilustrasi, sesuai deskripsi patch) — akumulasi di []byte,
// materialize ke string cuma sekali setelah parsing kelar
n.dataBuf = append(n.dataBuf, text...)
// ... di akhir proses parse:
n.Data = string(n.dataBuf)

For CVE-2026-97045, the fix is to always walk the full ancestor chain and verify that every transition from a non-empty namespace actually occurs exactly at an HTML integration point, rather than just stopping at the first integration point found.

Both bugs affect anyone calling html.Parse or render functions from golang.org/x/net/html on untrusted input — including dependencies that use it transitively. Here's an example of the relevant usage pattern (my own illustration, not from the source):

import (
    "net/http"
    "golang.org/x/net/html"
)

func handler(w http.ResponseWriter, r *http.Request) {
    doc, err := html.Parse(r.Body) // body request = input tidak terpercaya
    if err != nil {
        http.Error(w, "bad html", http.StatusBadRequest)
        return
    }
    _ = doc
}

Impact and Upgrade Notes

This announcement comes from the official golang-announce mailing list and was forwarded to oss-security by Alan Coopersmith. What needs checking: whether your service (directly or through a dependency) calls the HTML parser from golang.org/x/net/html on external input — for example an HTML sanitizer, a content proxy, or a scraping tool. The safest step is to update the dependency:

go get -u golang.org/x/net@latest
go mod tidy

After that, re-run the test suite, especially if you have tests that parse HTML with mixed SVG/MathML content, since the change in childTextNodesAreLiteral touches that namespace resolution logic. Full details and the official release numbers are in Go issue 82224 (CVE-2026-78661) and Go issue 82622 (CVE-2026-97045).

---

First announced on the oss-security mailing list. Read the original source for full details.

Read also