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.


Prevention & Best Practices

1. Keep golang.org/x/text (and all x/ packages) current

The golang.org/x/ packages are maintained by the Go team and receive security patches. Unlike the standard library, they are not bundled with Go releases, so you must upgrade them explicitly. Add them to your dependency audit process.

# Check for known vulnerabilities in your Go modules
govulncheck ./...

# Or use Trivy for container/filesystem scanning
trivy fs --scanners vuln .

2. Validate UTF-8 before passing to normalization routines

Even after upgrading, it's good practice to validate or sanitize input before feeding it to Unicode processing:

import (
    "unicode/utf8"
    "golang.org/x/text/unicode/norm"
)

func safeNormalize(input []byte) (string, error) {
    if !utf8.Valid(input) {
        return "", fmt.Errorf("input contains invalid UTF-8")
    }
    return norm.NFC.String(string(input)), nil
}

3. Set processing timeouts

Regardless of library versions, always wrap potentially long-running text processing in goroutines with context timeouts. This limits the blast radius of any future DoS bug:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

resultCh := make(chan string, 1)
go func() { resultCh <- processText(input) }()

select {
case result := <-resultCh:
    return result, nil
case <-ctx.Done():
    return "", fmt.Errorf("text processing timed out")
}

4. Use govulncheck in CI

The Go team's official vulnerability checker scans your code's actual call graph, not just your dependency list. It will only alert on vulnerabilities reachable from your code:

# .github/workflows/security.yml
- name: Run govulncheck
  run: |
    go install golang.org/x/vuln/cmd/govulncheck@latest
    govulncheck ./...

5. Relevant security standards


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.


References

Frequently Asked Questions

What is a norm.Iter infinite loop vulnerability?

It is a bug where the Unicode normalization iterator norm.Iter in golang.org/x/text gets stuck processing invalid UTF-8 input, never reaching a termination condition and consuming 100% CPU indefinitely.

How do you prevent infinite loop DoS vulnerabilities in Go?

Keep dependencies like golang.org/x/text up to date, validate or sanitize UTF-8 input before passing it to normalization routines, and set request/processing timeouts so a stuck goroutine cannot block indefinitely.

What CWE is this norm.Iter vulnerability?

CWE-835: Loop with Unreachable Exit Condition — the loop's exit condition can never be satisfied when malformed input is supplied.

Is input length limiting enough to prevent this vulnerability?

No. Even a short but specifically malformed UTF-8 sequence can trigger the infinite loop; the fix must be in the library's iterator logic itself, which is addressed by upgrading to v0.39.0.

Can static analysis detect this vulnerability?

Yes. Trivy's dependency scanner flagged this vulnerability by matching the golang.org/x/text version in go.mod against its CVE database, which is exactly how this fix was generated.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #2033

Related Articles

high

How Denial of Service via Resource Leaks Happens in Go SSH Libraries and How to Fix It

A Denial of Service vulnerability in `golang.org/x/crypto/ssh` (CVE-2026-39830) allowed attackers to exhaust server resources by sending unsolicited SSH responses that were never properly cleaned up. The fix upgrades `golang.org/x/crypto` from `v0.50.0` to `v0.52.0` in `go.mod`, patching the resource leak in the SSH package's response handling logic. Any Go application that uses the `golang.org/x/crypto/ssh` package for SSH client or server functionality was potentially exposed.

high

How SSH channel exhaustion happens in Go crypto and how to fix it

CVE-2026-39827 is a high-severity resource exhaustion vulnerability in `golang.org/x/crypto` where an authenticated SSH client can repeatedly open channels to consume server resources without bound. The vulnerability was present in the `cloud/gcp/functions/acmedns` module at version `v0.49.0` and was resolved by upgrading to `v0.52.0`. Left unpatched, this flaw could allow an attacker with valid SSH credentials to degrade or deny service to other users of the affected GCP Cloud Function.

high

How improper handling of case sensitivity happens in Go MCP SDK and how to fix it

A high-severity vulnerability (CVE-2026-27896) in the Model Context Protocol Go SDK v1.3.0 allowed attackers to bypass security controls through improper handling of case sensitivity. The fix upgrades the dependency from v1.3.0 to v1.3.1, which correctly normalizes case comparisons. This vulnerability was particularly concerning for CLI tools where attackers could manipulate input to evade validation logic.

high

How Denial of Service in SSH Key Exchange happens in Go golang.org/x/crypto and how to fix it

A high-severity denial of service vulnerability (CVE-2025-22869) was discovered in the SSH key exchange implementation of Go's `golang.org/x/crypto` library. The `cpdaemon` service depended on the vulnerable version v0.32.0, which could allow an attacker to exhaust server resources during the SSH handshake phase. The fix upgrades the dependency to v0.35.0, which includes the upstream patch for this vulnerability.

high

Authorization Bypass in gRPC-Go HTTP/2 Path Validation (CVE-2026-33186)

A critical authorization bypass vulnerability (CVE-2026-33186) in `google.golang.org/grpc` v1.79.1 allowed attackers to circumvent gRPC authorization policies through malformed HTTP/2 path values. The fix upgrades the dependency in `src/go/go.mod` from v1.79.1 to v1.79.3, closing a path validation gap in the `grpc-go/authz` middleware that could have exposed protected RPC endpoints to unauthorized callers.

high

How Unauthenticated Denial of Service happens in React Router and how to fix it

CVE-2026-55685 is a high-severity Denial of Service vulnerability in React Router's `@remix-run/server-runtime` that allows unauthenticated attackers to exhaust server resources by sending crafted requests to the manifest endpoint. The fix upgrades `react-router` from version 7.17.0 to 7.18.0, which tightens handling of untrusted input in route matching logic. Developers using any React Router 7.x application with server-side rendering should apply this patch immediately.