Back to Blog
high SEVERITY6 min read

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

A high-severity denial of service vulnerability (CVE-2026-32287) was discovered in the `github.com/antchfx/xpath` Go library, where crafted boolean XPath expressions could trigger an infinite loop, consuming CPU resources indefinitely. The fix upgrades the dependency from v1.3.3 to v1.3.6 in the `go.mod` file of the affected project. This vulnerability is particularly dangerous for any Go application that parses or evaluates XPath expressions from untrusted input.

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

Answer Summary

CVE-2026-32287 is a high-severity Denial of Service vulnerability in the Go library `github.com/antchfx/xpath` (versions prior to 1.3.6), classified under CWE-835 (Loop with Unreachable Exit Condition). Specially crafted boolean XPath expressions cause the XPath evaluation engine to enter an infinite loop, exhausting CPU resources. The fix is to upgrade the `antchfx/xpath` dependency to version 1.3.6 or later in your `go.mod` file, which patches the loop termination logic for boolean expression evaluation.

Vulnerability at a Glance

cweCWE-835
fixUpgrade github.com/antchfx/xpath from v1.3.3 to v1.3.6
riskApplication hangs indefinitely, consuming CPU and becoming unresponsive
languageGo
root causeBoolean XPath expression evaluation logic lacks proper loop termination
vulnerabilityDenial of Service (Infinite Loop)

Introduction

In the slurpcode/slurp Go project, a high-severity vulnerability was identified in the dependency tree through the go.mod file. The project depends on github.com/antchfx/xpath at version v1.3.3, which contains a critical flaw: certain boolean XPath expressions can cause the evaluation engine to enter an infinite loop, effectively hanging the application and consuming all available CPU resources.

This matters because the slurp project uses github.com/gocolly/colly/v2 for web scraping, which transitively depends on antchfx/htmlquery and antchfx/xmlquery—both of which rely on antchfx/xpath for XPath expression evaluation. Any scraped HTML or XML content that triggers XPath evaluation with a malicious boolean expression could bring the entire application to a halt.

The Vulnerability Explained

What Goes Wrong

The github.com/antchfx/xpath library is a Go implementation of the XPath 1.0 specification, used to navigate and query XML/HTML document trees. When evaluating boolean XPath expressions (expressions using and, or, not(), true(), false(), or comparison operators), the library's internal evaluation loop in versions prior to 1.3.6 can fail to reach its exit condition under specific crafted inputs.

Consider the dependency chain in this project:

github.com/gocolly/colly/v2
  → github.com/antchfx/htmlquery v1.3.4
    → github.com/antchfx/xpath v1.3.3  ← VULNERABLE
  → github.com/antchfx/xmlquery v1.4.4
    → github.com/antchfx/xpath v1.3.3  ← VULNERABLE

Attack Scenario

An attacker who can influence the content being scraped—or who can inject XPath expressions into the application's query logic—could craft a boolean XPath expression that triggers the infinite loop. For example:

  1. The slurp application uses Colly to scrape a web page
  2. The scraping logic uses XPath selectors (via htmlquery or xmlquery) to extract data
  3. If an attacker controls a page being scraped, they could structure the DOM in a way that, combined with certain XPath boolean predicates, triggers the infinite loop
  4. Alternatively, if the application accepts user-provided XPath expressions, a direct attack payload could be submitted

The result: the goroutine evaluating the XPath expression never returns, the CPU spins at 100%, and the application becomes completely unresponsive. In a server context, this is a classic resource exhaustion DoS.

Real-World Impact

For the slurp project specifically:
- Web scraping becomes a DoS vector: Any malicious website in the crawl queue could hang the scraper
- Resource exhaustion: In containerized deployments, this could trigger OOM kills or CPU throttling affecting co-located services
- No timeout recovery: Without explicit context cancellation, the infinite loop persists until the process is killed

The Fix

The fix is straightforward but comprehensive—upgrading the vulnerable dependency and its ecosystem of related packages to ensure compatibility:

Before (Vulnerable)

// go.mod - vulnerable dependency versions
require (
    github.com/antchfx/htmlquery v1.3.4 // indirect
    github.com/antchfx/xmlquery v1.4.4 // indirect
    github.com/antchfx/xpath v1.3.3 // indirect  ← VULNERABLE
)

After (Fixed)

// go.mod - patched dependency versions
require (
    github.com/antchfx/htmlquery v1.3.5 // indirect
    github.com/antchfx/xmlquery v1.5.0 // indirect
    github.com/antchfx/xpath v1.3.6 // indirect  ← PATCHED
)

Why Multiple Dependencies Changed

The fix wasn't limited to just bumping antchfx/xpath. Several related changes were necessary:

  1. github.com/antchfx/xpath v1.3.3 → v1.3.6: The core fix—patches the infinite loop in boolean expression evaluation
  2. github.com/antchfx/htmlquery v1.3.4 → v1.3.5: Updated to depend on the patched xpath version
  3. github.com/antchfx/xmlquery v1.4.4 → v1.5.0: Same reason—ensures the new xpath version is pulled in
  4. github.com/PuerkitoBio/goquery v1.10.2 → v1.11.0: Compatibility update
  5. golang.org/x/net v0.38.0 → v0.47.0: Transitive dependency update for compatibility
  6. golang.org/x/text v0.23.0 → v0.31.0: Transitive dependency update
  7. Go version 1.23.01.24.0: Minimum Go version bumped to support newer dependency features

Additionally, a duplicate dependency line was cleaned up:

// Before: duplicate entry
github.com/urfave/cli/v3 v3.11.0
github.com/urfave/cli/v3 v3.11.0

// After: corrected to single entry
github.com/urfave/cli/v2 v2.27.7

This is important because the go.mod file is the single source of truth for dependency resolution in Go modules. The go.sum file was also updated to reflect the new checksums for all updated packages.

Prevention & Best Practices

1. Automated Dependency Scanning

Use tools like Trivy, Snyk, or Go's native govulncheck to continuously monitor your dependency tree:

# Check for known vulnerabilities in Go dependencies
govulncheck ./...

# Or using Trivy
trivy fs --scanners vuln .

2. Pin and Audit Dependencies

Always review what your transitive dependencies pull in. In this case, the vulnerability was three levels deep in the dependency tree:

your-app → colly → htmlquery → xpath (vulnerable)

3. Implement Timeouts for XPath Evaluation

Even with patched libraries, defense in depth matters:

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

// Use context-aware APIs where available
result, err := htmlquery.QueryWithContext(ctx, doc, xpathExpr)

4. Validate XPath Expressions

If your application accepts user-provided XPath expressions, validate them before evaluation:

// Compile XPath to catch syntax errors early
_, err := xpath.Compile(userProvidedXPath)
if err != nil {
    return fmt.Errorf("invalid xpath expression: %w", err)
}

5. Keep Dependencies Current

Set up automated dependency update tools (Dependabot, Renovate, or Orbis AppSec) to receive timely notifications about security patches.

Key Takeaways

  • Transitive dependencies are attack surface: The vulnerable antchfx/xpath v1.3.3 was never directly imported by slurp, but it was reachable through Colly's HTML/XML query packages—making it exploitable through the scraping pipeline.
  • Boolean XPath expressions are a non-obvious DoS vector: Developers rarely think of XPath boolean logic as dangerous, but the infinite loop in antchfx/xpath proves that any input-processing loop without guaranteed termination is a risk.
  • Dependency upgrades often cascade: Fixing one library (xpath v1.3.3 → v1.3.6) required updating five other packages and the Go version itself to maintain compatibility—this is why automated tooling is essential.
  • Duplicate dependency entries (urfave/cli/v3 listed twice) signal maintenance debt: The go.mod file had a duplicate line that was also corrected in this fix, suggesting the dependency file hadn't been carefully reviewed recently.
  • "Not confirmed reachable" still warrants fixing: Even though the scanner noted the vulnerability was "present in dependency tree, not confirmed reachable," the fix was applied because the Colly scraping pipeline makes XPath evaluation highly likely during normal operation.

How Orbis AppSec Detected This

  • Source: Untrusted HTML/XML content fetched during web scraping via github.com/gocolly/colly/v2, which passes document trees to XPath evaluation
  • Sink: github.com/antchfx/xpath v1.3.3 boolean expression evaluation engine (internal loop with unreachable exit condition)
  • Missing control: No loop termination guarantee in the xpath library's boolean expression evaluator; no timeout wrapper around XPath evaluation calls
  • CWE: CWE-835 (Loop with Unreachable Exit Condition)
  • Fix: Upgraded github.com/antchfx/xpath from v1.3.3 to v1.3.6, which patches the boolean expression evaluation loop to guarantee termination

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-32287 demonstrates a subtle but dangerous class of vulnerability: infinite loops triggered by crafted input in parsing libraries. The antchfx/xpath library is widely used across the Go ecosystem for HTML and XML processing, making this a high-impact issue. The fix—upgrading from v1.3.3 to v1.3.6—is simple to apply but required careful coordination of multiple transitive dependencies.

For Go developers working with web scraping, XML processing, or any XPath evaluation: audit your go.mod for the vulnerable version, apply the upgrade, and consider adding context timeouts around XPath operations as an additional layer of defense. The cost of a dependency upgrade is trivial compared to the cost of a production DoS incident.

References

Frequently Asked Questions

What is a Denial of Service via infinite loop?

It's a vulnerability where specially crafted input causes a program to enter an endless loop, consuming CPU resources and making the application unresponsive to legitimate requests.

How do you prevent infinite loop DoS in Go?

Use context timeouts for operations processing untrusted input, keep dependencies updated, validate and sanitize XPath expressions before evaluation, and implement resource limits on computation time.

What CWE is an infinite loop vulnerability?

CWE-835 (Loop with Unreachable Exit Condition) covers vulnerabilities where a loop cannot reach its exit condition, leading to resource exhaustion.

Is input validation enough to prevent XPath DoS?

Input validation helps but is not sufficient alone—complex boolean expressions may pass validation yet still trigger the bug. Upgrading to the patched library version is the definitive fix.

Can static analysis detect infinite loop vulnerabilities?

Yes, tools like Trivy (for known CVEs in dependencies), Semgrep, and Go's govulncheck can detect known vulnerable dependency versions and some loop patterns, though novel infinite loops in third-party code often require CVE databases.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #3537

Related Articles

critical

How Command Injection via Unescaped Line Terminators Happens in Node.js and How to Fix It

A critical command injection vulnerability (CVE-2026-9277) was discovered in the shell-quote npm package version 1.8.3, where unescaped line terminators could allow attackers to execute arbitrary code. This fix upgrades shell-quote to version 1.9.0 using npm overrides to ensure all instances in the dependency tree are patched, eliminating the attack vector across the entire application.

critical

How Distributed Lock Takeover Happens in Node.js and How to Fix It

A critical vulnerability in `redis-lock/server.mjs` allowed any authenticated client to release another client's lock by guessing predictable holder identifiers like process IDs or hostnames. The fix implements cryptographically random `lockId` values that are minted on lock acquisition and validated on release, eliminating the exploit primitive entirely.

high

How Denial of Service via Infinite Loop happens in JavaScript (nanoid) and how to fix it

A high-severity denial of service vulnerability (CVE-2026-67213) was discovered in nanoid versions before 5.1.6 and 3.3.18, where the `customAlphabet` function could enter an infinite loop during random ID generation. The fix upgrades the transitive nanoid dependency from 3.3.16 to 3.3.18 using pnpm overrides, ensuring the vulnerable code path is eliminated from the entire dependency tree including PostCSS.

high

How Information Disclosure via Unstripped Credential Headers Happens in Electron Apps and How to Fix It

A high-severity vulnerability (CVE-2026-54673) in the builder-util-runtime package allowed sensitive credential headers to leak during HTTP redirects in Electron applications. The fix upgrades builder-util-runtime from version 9.5.1 to 9.7.0, which properly strips authentication headers before following redirects to prevent information disclosure.

high

How Command Injection happens in PHP and how to fix it

A high-severity command injection vulnerability was discovered in `lib/Controller/Helper.php` where the `corruptline()` method used `exec()` to run sed and awk commands with user-controlled input. The fix replaced all shell command execution with native PHP file operations using `SplFileObject`, eliminating the command injection attack surface entirely.

high

How Missing CSRF Middleware happens in Express.js and how to fix it

A high-severity CSRF vulnerability was discovered in `libProxy.js` of an Express.js application — the app had no CSRF middleware protecting its state-changing routes, leaving them open to cross-site request forgery attacks. The fix introduces a `csrf` token library, a `/csrf-token` endpoint to issue tokens, and a middleware that validates `x-csrf-token` headers or `_csrf` body fields on all non-safe HTTP methods. This proactive hardening removes an exploit primitive that could be chained with ot