Feb 13, 2026·7 min read·75 visits
The Go HTML parser (`x/net/html`) contains a quadratic complexity bug in its tree construction logic. An attacker can send a malicious HTML payload (like deeply nested or malformed tags) that causes the parser to consume excessive CPU resources, effectively hanging the application. Fix: Upgrade `golang.org/x/net` to v0.45.0.
In the world of safe memory languages, we often forget that algorithmic complexity is a vulnerability class of its own. CVE-2025-47911 serves as a stark reminder: you don't need a buffer overflow to kill a server; you just need a really annoying HTML table. This vulnerability affects the `golang.org/x/net/html` package—the de facto standard for HTML parsing in the Go ecosystem—allowing attackers to trigger quadratic time complexity ($O(n^2)$) during the parsing of specially crafted inputs.
We've all been there. You need to parse some HTML. Maybe you're building a web crawler, a link preview generator, or an email sanitizer. You know better than to use Regex (because Zalgo comes), so you reach for the gold standard: golang.org/x/net/html. It's robust, it's maintained by the Go team, and it implements the HTML5 specification. What could go wrong?
Here is the thing about specifications: the HTML5 spec is a nightmare of backward compatibility and error recovery. It is designed to handle the absolute garbage markup that the internet produced in the 90s. This means the parser has to be smart. It has to fix your mistakes. It has to re-parent elements, close unclosed tags, and basically guess what the developer meant.
CVE-2025-47911 is what happens when that helpfulness turns toxic. By feeding the parser a specifically crafted sequence of garbage—think thousands of misaligned select or table tags—we can force the parser into a "panic mode" of sorts. It doesn't crash (panic) in the Go sense; instead, it enters a state of algorithmic despair, frantically walking up and down the element stack, consuming CPU cycles like they're free candy. It's a classic Algorithmic Complexity Denial of Service, and it turns your shiny Go microservice into a brick.
To understand this bug, you have to understand one of the most cursed parts of the HTML5 spec: the Adoption Agency Algorithm. This logic handles cases where formatting elements (like b, i, font) are closed in the wrong order or interrupted by block elements. For example, if you write <b><p>Text</b></p>, the browser (and the Go parser) has to figure out how to close the b tag before the p starts, or extend it into the p.
In the x/net/html implementation, the parser maintains a stack of open elements. When it encounters certain tags in specific states, it has to iterate through this stack to find a matching formatting element or to perform "fostering" of orphan elements (common in table parsing).
The vulnerability arises because the code failed to cap the number of iterations required for these stack fix-ups relative to the input size. If I send you an HTML document with 10,000 nested formatting elements interlaced with table elements, the parser might have to scan a significant portion of that 10,000-deep stack for every new tag I insert.
Mathematically, we are looking at $O(n^2)$ complexity. If $N=10,000$, $N^2 = 100,000,000$ operations. That transforms a 10KB payload processing time from milliseconds to seconds (or minutes), freezing the Goroutine responsible for the request.
The fix provided in CL 709876 is a textbook example of "defensive coding 101: always have an exit strategy." The original code would happily iterate through lists of active formatting elements without a hard stop, trusting that the stack wouldn't be maliciously deep. The patch introduces a constant overhead limit.
Here is a conceptual look at the vulnerable logic flow versus the patched logic:
// Vulnerable logic (simplified)
for {
// Walk up the stack looking for specific elements
// If the stack is 50,000 items deep, this loop runs 50,000 times
entry := findFormattingElement(stack)
if entry == nil {
break
}
// complex tree manipulation logic...
}The fix introduces a sanity check. It acknowledges that valid HTML shouldn't require thousands of stack adoption steps.
// Patched logic (simplified)
const maxIterations = 1000 // A sane limit
for i := 0; i < maxIterations; i++ {
entry := findFormattingElement(stack)
if entry == nil {
break
}
// complex tree manipulation logic...
}
if loopHitLimit {
// Stop trying to be smart. Just return or handle as error.
return
}By capping the loop, the complexity drops back towards linear $O(n)$. The parser might produce a slightly "wrong" tree for an insanely complex malicious input, but crucially, it finishes parsing.
Exploiting this doesn't require binary ninja skills; it requires a Python script and a bit of creativity. The goal is to maximize the work done by html.Parse per byte of input.
Target: A Markdown-to-HTML converter or a link preview service (e.g., Slack/Discord style previews) running on a vulnerable Go backend.
The most effective payloads typically involve abusing <table>, <select>, or <frameset> tags because they trigger specific complex modes in the parser state machine.
# PoC Generator for CVE-2025-47911
# Generates a payload that abuses the table adoption agency logic
payload = "<table>"
# Create a deep stack of formatting elements
for i in range(5000):
payload += "<b><i>"
# Trigger the parser to walk the stack repeatedly
for i in range(5000):
payload += "<p>Trigger Reconstruct</p>"
print(payload)When x/net/html parses this, every <p> tag inside that unclosed <table> forces the parser to reconcile the stack of 10,000 <b><i> tags.
> [!NOTE]
> Real-world impact depends on the server's timeout settings. However, since html.Parse is often called before any application-level timeouts (like context.WithTimeout) can interrupt the CPU-bound work, the Go runtime might not be able to schedule the cancellation effectively until a GC pause or function return.
You might look at the CVSS score of 5.3 and think, "Medium severity? I'll patch it next month." That would be a mistake. CVSS scores for DoS often fail to capture the operational reality of modern architecture.
In a Kubernetes environment, a single pod often handles concurrent requests. If you are running a single-threaded Node.js app, one request kills the server. Go handles concurrency better via Goroutines, but this bug is CPU-bound. If an attacker sends 4-8 concurrent requests (matching your CPU core count), they can peg the CPU at 100%.
The Domino Effect:
Affected systems include critical infrastructure pieces like Grafana, Helm, and Podman. If you use these tools to render user-supplied content, you are vulnerable.
The mitigation here is boring, which is good. You don't need to rewrite your architecture; you just need to bump a dependency.
Remediation Steps:
govulncheck ./...go get golang.org/x/net@v0.45.0
go mod tidyIf you cannot patch immediately (e.g., frozen codebase), you must implement strict input size limits before calling the parser. Truncating HTML input to a reasonable size (e.g., 50KB) can mitigate the worst of the $O(n^2)$ effects, turning a 10-second hang into a 100ms hiccup. However, truncation can break valid HTML, so patching is the only clean solution.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
golang.org/x/net Golang | < v0.45.0 | v0.45.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 (Uncontrolled Resource Consumption) |
| Attack Vector | Network |
| CVSS v3.1 | 5.3 (Medium) |
| Impact | Denial of Service (CPU Exhaustion) |
| Patch | golang.org/x/net v0.45.0 |
| Exploit Status | PoC Available (Trivial to construct) |
CVE-2026-48861 is a client-side HTTP request-line CRLF (Carriage Return Line Feed) injection vulnerability in the popular Elixir HTTP client library, Mint. The vulnerability permits HTTP Request Splitting and HTTP Request Smuggling when an application forwards untrusted, attacker-controlled inputs to Mint's HTTP client requests as either the HTTP request method or target. By embedding CRLF characters within these parameters, an attacker can terminate the request line prematurely, inject malicious headers, or pipeline entirely independent requests. These smuggled requests are then processed by upstream or downstream proxy servers as separate HTTP queries on the same TCP connection. While Mint version 1.7.0 introduced target validation to secure the request target, the HTTP request method parameter remained completely unvalidated. This flaw allows attackers to bypass routing filters, access restricted internal APIs, or poison HTTP caches under default configurations.
An Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling) vulnerability in the Elixir Mint HTTP client allows attacker-controlled HTTP/1 servers to desynchronize response framing on shared connections due to over-lenient parsing of sign-prefixed Content-Length headers.
An allocation of resources without limits or throttling vulnerability in Elixir Mint allows an attacker-controlled HTTP/2 server to exhaust memory in a Mint client. The vulnerability is exploited by sending a HEADERS frame without the END_HEADERS flag followed by an infinite stream of CONTINUATION frames. Because the client lacks limits on the incoming header-block accumulator, the client continuously consumes memory until an out-of-memory crash occurs.
CVE-2026-48596 is an Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting, CWE-113) in the Elixir Tesla HTTP client. The flaw resides in how multipart content-type parameters are joined and serialized, enabling attackers to inject arbitrary headers or split HTTP requests when applications pass untrusted inputs to the parameters of multipart uploads.
An improper handling of highly compressed data (decompression bomb) vulnerability exists in the Elixir Tesla HTTP client when utilizing response decompression middlewares. By serving highly compressed responses or stacked content-encoding headers, a malicious server can cause arbitrary heap exhaustion, leading to a denial of service (DoS) crash in the BEAM virtual machine.
A high-severity security vulnerability in Elixir's Tesla HTTP client library (CVE-2026-48595) allows unauthenticated remote attackers to harvest sensitive credentials, including Authorization headers and cookies. The flaw resides in the 'Tesla.Middleware.FollowRedirects' component, which performs case-sensitive lookups when stripping credentials during cross-origin redirects. Because HTTP headers are case-insensitive by RFC specifications, standard canonical casing (e.g., 'Authorization') bypasses the lowercase-only blocklist, leaking tokens to untrusted external redirect destinations.