CVE-2026-113729 is a high-severity (CVSS 7.5) Uncontrolled Resource Consumption vulnerability in github.com/moov-io/signedxml. A fix is available for github.com/moov-io/signedxml — see the affected versions and patch details below.
Moov signedxml: Unauthenticated denial of service in exclusive XML canonicalization
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
CVE-2026-113729 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.
Where this sits among everything scored
Of 394,415 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.
Real-World Exposure
github.com/moov-io/signedxmlReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
Exclusive XML canonicalization (http://www.w3.org/2001/10/xml-exc-c14n#) in github.com/moov-io/signedxml copied the entire accumulated namespace map at every node during ValidateReferences(), before any reference digest or signature check.
For a chain of nested elements that each declare many unused namespace prefixes, that produced O(m × depth²) time and peak memory (m = prefixes per level). beevik/etree caps tree depth (~1024), but m is unbounded, so a small attacker-controlled document (on the order of 1 MB) could drive multi-gigabyte allocations and OOM the process. No valid signature, matching certificate, or authentication is required.
This is the library’s core path for SAML / WS-Federation service providers, which canonicalize attacker-supplied XML prior to authentication.
Affected
- Package:
github.com/moov-io/signedxml - Function:
ExclusiveCanonicalization(exclusivecanonicalization.go) - Verified: v1.4.0 and current default branch (commit
d79064a). Earlier v1.2.x–v1.3.x releases are likely affected.
Remediation
Do not copy the whole namespace map per node. Maintain a single scope and push/pop only the prefixes introduced at each element. Replace linear prefix-in-scope scans with set lookups. Impose a defensive cap on in-scope namespace declarations and return an error rather than allocating unbounded memory.
From @shuji-oh
Thanks for the fix — I re-ran my PoC against this branch and confirmed the memory blowup is gone.
Before (main)
-- Doubling depth each time (m=10 fixed): allocated grows ~4x each time ≈ O(depth^2) --
depth=250 m=10 payload= 0.07MB allocated= 45MB
depth=500 m=10 payload= 0.14MB allocated= 179MB
depth=1000 m=10 payload= 0.27MB allocated= 711MB
-- Increasing m (depth=1000 fixed): allocated scales roughly linearly with m --
depth=1000 m=5 payload= 0.16MB allocated= 377MB
depth=1000 m=100 payload= 2.57MB allocated= 6278MB
After (fix/exc-c14n-namespace-dos)
-- Doubling depth each time (m=10 fixed): allocated grows ~4x each time ≈ O(depth^2) --
depth=250 m=10 payload= 0.07MB allocated= 2MB
depth=500 m=10 payload= 0.14MB allocated= 4MB
depth=1000 m=10 payload= 0.27MB allocated= 7MB
-- Increasing m (depth=1000 fixed): allocated scales roughly linearly with m --
depth=1000 m=5 payload= 0.16MB allocated= 4MB
depth=1000 m=100 payload= 2.57MB allocated= 47MB
That's roughly a 100–130x reduction in peak allocation for the same payload sizes, and no OOM in any of my runs. This looks like it resolves the issue — thanks for the quick fix!
Credit
Reported by Shuji Ohira (@shuji-oh).
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/moov-io/signedxml | all versions | 1.4.1go get github.com/moov-io/signedxml@v1.4.1 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/moov-io/signedxml, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update github.com/moov-io/signedxml to 1.4.1 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-113729 is resolved across your whole dependency graph.
Workarounds
Cap what an attacker can consume: apply request size, rate and timeout limits in front of the affected component, and run it with memory and CPU limits so exhaustion degrades one worker rather than the whole service.
Frequently Asked Questions
Is CVE-2026-113729 in your dependencies?
Find it across Go, including transitive dependencies.