CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2025-47911

Death by a Thousand Tags: The Quadratic HTML DoS in Go

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 13, 2026·7 min read·75 visits

Executive Summary (TL;DR)

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.

The Hook: When Parsing Goes Wrong

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.

The Flaw: The Adoption Agency Algorithm

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 Code: Limits? We Don't Need Limits.

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.

The Exploit: Building the Stairway to Hang

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.

The Attack Scenario

Target: A Markdown-to-HTML converter or a link preview service (e.g., Slack/Discord style previews) running on a vulnerable Go backend.

The Payload

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.

The Impact: Why You Should Care

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:

  1. Liveness Probes Fail: Kubernetes sees the CPU spike and the lack of response. It kills the pod.
  2. Respawn Storm: The pod restarts. The attacker sends the payload again immediately.
  3. Cascading Failure: If the parser is part of a queue consumer (e.g., processing emails), the malicious payload might remain in the queue. Every time a worker picks it up, it dies. You now have a poisoned queue blocking all valid traffic.

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 Fix: Just Update It

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:

  1. Identify vulnerable dependencies:
    govulncheck ./...
  2. Update the package:
    go get golang.org/x/net@v0.45.0
    go mod tidy
  3. Rebuild and redeploy.

If 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.

Official Patches

GolangGerrit Change List for the fix
GolangGo Vulnerability Database Entry

Fix Analysis (1)

Technical Appendix

CVSS Score
5.3/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
EPSS Probability
0.06%

Affected Systems

GrafanaHelmPodmanEcho Web FrameworkKubernetes Controllers (using html templates)Email Sanitizers (using x/net/html)

Affected Versions Detail

Product
Affected Versions
Fixed Version
golang.org/x/net
Golang
< v0.45.0v0.45.0
AttributeDetail
CWE IDCWE-400 (Uncontrolled Resource Consumption)
Attack VectorNetwork
CVSS v3.15.3 (Medium)
ImpactDenial of Service (CPU Exhaustion)
Patchgolang.org/x/net v0.45.0
Exploit StatusPoC Available (Trivial to construct)

MITRE ATT&CK Mapping

T1499.002Service Exhaustion
Impact
CWE-400
Uncontrolled Resource Consumption

Vulnerability Timeline

Patch released in golang.org/x/net v0.45.0
2026-02-02
CVE-2025-47911 Published
2026-02-05
GO-2026-4440 Published
2026-02-05

More Reports

•about 8 hours ago•CVE-2026-48861
2.1

CVE-2026-48861: HTTP Request Splitting and Smuggling via Method Parameter CRLF Injection in Elixir Mint

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.

Amit Schendel
Amit Schendel
6 views•7 min read
•about 9 hours ago•CVE-2026-49753
6.3

CVE-2026-49753: HTTP Request/Response Smuggling via Inconsistent Content-Length Parsing in Elixir Mint Client

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.

Amit Schendel
Amit Schendel
6 views•6 min read
•about 9 hours ago•CVE-2026-49754
8.2

CVE-2026-49754: Denial of Service via Unbounded HTTP/2 CONTINUATION Frame Accumulation in Elixir Mint

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.

Amit Schendel
Amit Schendel
7 views•6 min read
•about 10 hours ago•CVE-2026-48596
2.1

CVE-2026-48596: Improper Neutralization of CRLF Sequences in Elixir Tesla Multipart HTTP Client

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.

Alon Barad
Alon Barad
5 views•6 min read
•about 10 hours ago•CVE-2026-48594
8.2

CVE-2026-48594: Decompression Bomb Denial of Service in Elixir Tesla HTTP Client

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.

Amit Schendel
Amit Schendel
6 views•6 min read
•about 11 hours ago•CVE-2026-48595
8.2

CVE-2026-48595: Cross-Origin Credential Leakage in Elixir Tesla Client via Case-Sensitive Redirect Filter Bypass

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.

Alon Barad
Alon Barad
6 views•5 min read