Back to Blog
high SEVERITY8 min read

How Denial of Service via Infinite Loop happens in Go and how to fix it

CVE-2026-56852 is a high-severity Denial of Service vulnerability in the `golang.org/x/text` package where a `norm.Iter` iterator can enter an infinite loop when processing certain invalid UTF-8 input sequences. Applications using `golang.org/x/text` v0.37.0 or earlier that accept untrusted text input are at risk of complete service disruption. The fix is a one-line dependency bump in `go.mod` from v0.37.0 to v0.39.0.

O
By Orbis AppSec
Published August 10, 2026Reviewed August 10, 2026

Answer Summary

CVE-2026-56852 is a Denial of Service vulnerability (CWE-835: Loop with Unreachable Exit Condition) in the Go package `golang.org/x/text`. A `norm.Iter` iterator enters an infinite loop when it encounters specially crafted invalid UTF-8 byte sequences, allowing an attacker to permanently hang any goroutine processing that input. The fix is to upgrade `golang.org/x/text` from v0.37.0 to v0.39.0 in `go.mod` and `go.sum`, which corrects the iterator's handling of malformed Unicode data so it always terminates.

Vulnerability at a Glance

cweCWE-835 (Loop with Unreachable Exit Condition)
fixUpgrade golang.org/x/text from v0.37.0 to v0.39.0 in go.mod and go.sum
riskAttacker-controlled input can permanently hang a goroutine, exhausting server resources
languageGo
root causenorm.Iter in golang.org/x/text ≤0.37.0 fails to advance past certain invalid UTF-8 byte sequences, looping forever
vulnerabilityDenial of Service via Infinite Loop (norm.Iter on invalid UTF-8)

How Denial of Service via Infinite Loop Happens in Go and How to Fix It

The Vulnerability at a Glance

Field Detail
CVE CVE-2026-56852
Severity High
Package golang.org/x/text
Affected versions ≤ v0.37.0
Fixed version v0.39.0
CWE CWE-835: Loop with Unreachable Exit Condition
Impact Denial of Service (infinite CPU loop)

Introduction

The go.mod file in this repository declared a dependency on golang.org/x/text v0.37.0 — a widely used Go package for Unicode text processing, normalization, and encoding. Buried inside that package's normalization subsystem is a flaw in the norm.Iter iterator: when it encounters certain sequences of invalid UTF-8 bytes, it enters an infinite loop with no reachable exit condition. Any goroutine calling into that iterator with attacker-controlled input will spin forever at 100% CPU, never returning, and never releasing its resources.

For developers building APIs, CLIs, or data pipelines in Go that accept text from untrusted sources — user input, file uploads, network streams — this is a direct path to service unavailability. The Trivy scanner identified the vulnerable version pinned in go.mod and flagged it as likely exploitable.


The Vulnerability Explained

What is norm.Iter and why does it matter?

golang.org/x/text/unicode/norm provides Unicode normalization forms (NFC, NFD, NFKC, NFKD). The norm.Iter type is an iterator that walks through a byte slice, yielding normalized segments one at a time. It is used internally throughout the x/text ecosystem — in encoding transformers, language detection, collation, and anywhere the library needs to process text incrementally.

The iterator's core loop looks conceptually like this (simplified):

// Vulnerable pattern in norm.Iter (golang.org/x/text ≤ v0.37.0)
for !iter.Done() {
    segment := iter.Next() // <-- can return empty slice on invalid UTF-8
    process(segment)
}

The critical flaw: when iter.Next() encounters a specific class of invalid UTF-8 byte sequence, it returns an empty segment without advancing the internal byte-position cursor. The loop condition !iter.Done() remains true because the cursor hasn't moved past the bad bytes, and iter.Next() keeps returning empty without progressing. The loop has no reachable exit — it runs forever.

The vulnerable dependency declaration

The problem was pinned directly in go.mod:

// go.mod — BEFORE (vulnerable)
golang.org/x/text v0.37.0

And confirmed by the corresponding hash in go.sum:

// go.sum — BEFORE (vulnerable)
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=

How an attacker exploits this

Consider an HTTP API endpoint that accepts a JSON body containing a name or description field, and somewhere in the processing pipeline that string is passed through a Unicode normalization step — perhaps for case-folding, collation, or sanitization:

// Example vulnerable processing path
import "golang.org/x/text/unicode/norm"

func processUserInput(input []byte) string {
    var iter norm.Iter
    iter.Init(norm.NFC, input)  // input comes from HTTP request body

    var result []byte
    for !iter.Done() {
        result = append(result, iter.Next()...)  // infinite loop if input is malformed UTF-8
    }
    return string(result)
}

An attacker sends a POST request with a carefully crafted body containing the triggering invalid UTF-8 sequence. The goroutine handling that request enters the infinite loop. It never returns. The HTTP server's goroutine pool fills up with stuck handlers. New requests cannot be served. The service becomes completely unavailable — a full Denial of Service achieved with a single malformed request.

Because Go's HTTP server spawns a goroutine per request, an attacker doesn't even need high request volume. One request with the right malformed bytes is enough to permanently consume a goroutine; a handful of such requests can exhaust the pool entirely.

Real-world impact for this application

This repository uses golang.org/x/text alongside a MongoDB driver, Kubernetes client libraries (k8s.io/api, k8s.io/apimachinery), and cryptographic utilities. Any code path that normalizes, encodes, or collates text from external sources — database content, API responses, user-submitted data — could trigger this loop if the data contains invalid UTF-8. Given the breadth of the dependency graph, the attack surface is non-trivial.


The Fix

The fix is a targeted dependency upgrade in exactly two files: go.mod and go.sum.

go.mod — before and after

# go.mod
- golang.org/x/text v0.37.0
+ golang.org/x/text v0.39.0

This single line change tells the Go toolchain to resolve and link against v0.39.0 instead of v0.37.0. The v0.39.0 release patches the norm.Iter iterator so that it always advances its internal cursor past invalid UTF-8 bytes — even when it cannot produce a valid normalized segment — ensuring the loop's exit condition is always eventually reachable.

go.sum — cryptographic verification updated

# go.sum
- golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
- golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+ golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus=
+ golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM=

The go.sum file stores cryptographic hashes of every dependency module and its go.mod. Updating these hashes is mandatory — the Go toolchain will refuse to build if the hashes in go.sum don't match the downloaded module. This change ensures that the build is reproducibly pinned to the patched version and that no tampered intermediate version can be silently substituted.

Why only two files?

The fix is deliberately minimal. No application code changes are required because the bug lived entirely within the library's internal iterator logic. The public API surface of norm.IterInit(), Next(), Done() — is unchanged. Valid UTF-8 input continues to be processed identically. Only the handling of malformed input is tightened, and that tightening happens inside the library itself.


Key Takeaways

  • golang.org/x/text is not part of the Go standard library — it must be explicitly upgraded to receive security patches, and v0.37.0 is vulnerable to this infinite loop.
  • A single malformed HTTP request is sufficient to permanently hang a goroutine via the norm.Iter loop, making this a low-effort, high-impact DoS vector.
  • The go.sum hash update is not optional — both go.mod and go.sum must be updated together for the Go toolchain to accept and reproducibly build the patched version.
  • Unicode normalization routines are a non-obvious attack surface — any code path that collates, encodes, or normalizes user-supplied text may route through norm.Iter even if you never call it directly.
  • Trivy's dependency scanning caught this without requiring code-level analysis — pinning vulnerable versions in go.mod is itself a detectable, fixable security issue.

How Orbis AppSec Detected This

  • Source: Untrusted text input (e.g., HTTP request body, user-supplied string fields) passed into any function that internally calls norm.Iter.Next() within golang.org/x/text.
  • Sink: The norm.Iter.Next() call inside the normalization iterator loop in golang.org/x/text ≤ v0.37.0, reachable via any consumer of the unicode/norm package.
  • Missing control: The iterator lacked a guard to advance its cursor past invalid UTF-8 byte sequences, leaving the loop's exit condition permanently unsatisfiable on malformed input.
  • CWE: CWE-835 — Loop with Unreachable Exit Condition.
  • Fix: Upgraded golang.org/x/text from v0.37.0 to v0.39.0 in go.mod and updated the corresponding cryptographic hashes in go.sum.

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

CVE-2026-56852 is a sharp reminder that Denial of Service vulnerabilities don't always require sophisticated exploits. A handful of malformed bytes — specifically crafted invalid UTF-8 sequences — is all it takes to permanently hang a goroutine processing text with golang.org/x/text ≤ v0.37.0. The norm.Iter iterator's failure to advance past bad input creates a loop that can never exit, turning a routine text-processing call into a resource-exhaustion attack.

The fix is as minimal as it gets: two lines changed in go.mod, two lines updated in go.sum, and the vulnerability is closed. But finding it requires knowing to look — which is exactly what automated dependency scanning tools like Trivy and govulncheck are built to do. Make them a standard part of your Go CI pipeline, keep your x/ packages current, and treat your go.mod file as the security-critical artifact it truly is.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #2033

Related Articles

critical

deleteNestedProperty Prototype Pollution via Dot-Notation Path

The `deleteNestedProperty` function in propertyUtils.ts allowed attackers to manipulate JavaScript object prototypes by passing specially crafted dot-notation paths like `__proto__.polluted`. A fix now blocks dangerous keys before processing, preventing prototype pollution attacks that could affect all objects in the application.

high

How Denial of Service via Infinite Loop Happens in JavaScript Dependencies and How to Fix It

CVE-2026-67213 is a high-severity denial of service vulnerability in nanoid before version 5.1.6 that triggers an infinite loop during random ID generation when processing specially crafted input. We upgraded nanoid across the entire dependency tree to patch this flaw and prevent attackers from freezing application threads. This fix ensures that ID generation remains resilient even when handling adversarial input patterns.

high

How Sensitive Data Exposure happens in Zotero plugins and how to fix it

A high-severity data exposure vulnerability in `Zotero.ts` automatically transmitted complete document metadata—including private notes, attachment paths, and tags—to external LLM services without user consent. The fix replaces broad `item.toJSON()` serialization with explicit field selection, sending only essential bibliographic data.

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.