GHSA-5588-RP99-5FJH

Vulnerability from github – Published: 2026-10-21 16:27 – Updated: 2026-10-21 16:27
VLAI
Summary
Moov signedxml: Unauthenticated denial of service in exclusive XML canonicalization
Details

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

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.4.0"
      },
      "package": {
        "ecosystem": "Go",
        "name": "github.com/moov-io/signedxml"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.4.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-113729"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400",
      "CWE-407",
      "CWE-770"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-21T16:27:55Z",
    "nvd_published_at": "2026-10-20T22:19:29Z",
    "severity": "HIGH"
  },
  "details": "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.\n\nFor a chain of nested elements that each declare many unused namespace prefixes, that produced **O(m \u00d7 depth\u00b2)** 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.\n\nThis is the library\u2019s core path for SAML / WS-Federation service providers, which canonicalize attacker-supplied XML prior to authentication.\n\n### Affected\n\n- Package: `github.com/moov-io/signedxml`\n- Function: `ExclusiveCanonicalization` (`exclusivecanonicalization.go`)\n- Verified: **v1.4.0** and current default branch (commit `d79064a`). Earlier v1.2.x\u2013v1.3.x releases are likely affected.\n \n\n### Remediation\n\nDo 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.\n\nFrom @shuji-oh \n```\nThanks for the fix \u2014 I re-ran my PoC against this branch and confirmed the memory blowup is gone.\n\nBefore (main)\n\n-- Doubling depth each time (m=10 fixed): allocated grows ~4x each time \u2248 O(depth^2) --\ndepth=250  m=10  payload=  0.07MB allocated=     45MB\ndepth=500  m=10  payload=  0.14MB allocated=    179MB\ndepth=1000 m=10  payload=  0.27MB allocated=    711MB\n-- Increasing m (depth=1000 fixed): allocated scales roughly linearly with m --\ndepth=1000 m=5   payload=  0.16MB allocated=    377MB\ndepth=1000 m=100 payload=  2.57MB allocated=   6278MB\nAfter (fix/exc-c14n-namespace-dos)\n\n-- Doubling depth each time (m=10 fixed): allocated grows ~4x each time \u2248 O(depth^2) --\ndepth=250  m=10  payload=  0.07MB allocated=      2MB\ndepth=500  m=10  payload=  0.14MB allocated=      4MB\ndepth=1000 m=10  payload=  0.27MB allocated=      7MB\n-- Increasing m (depth=1000 fixed): allocated scales roughly linearly with m --\ndepth=1000 m=5   payload=  0.16MB allocated=      4MB\ndepth=1000 m=100 payload=  2.57MB allocated=     47MB\nThat\u0027s roughly a 100\u2013130x reduction in peak allocation for the same payload sizes, and no OOM in any of my runs. This looks like it resolves the issue \u2014 thanks for the quick fix!\n```\n\n### Credit\n\nReported by Shuji Ohira ([@shuji-oh](https://github.com/shuji-oh)).",
  "id": "GHSA-5588-rp99-5fjh",
  "modified": "2026-10-21T16:27:55Z",
  "published": "2026-10-21T16:27:55Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/moov-io/signedxml/security/advisories/GHSA-5588-rp99-5fjh"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-113729"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moov-io/signedxml/commit/da2cd6126c4c53b7e59a367d287786e6f6a2d0d3"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/moov-io/signedxml"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moov-io/signedxml/releases/tag/v1.4.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Moov signedxml: Unauthenticated denial of service in exclusive XML canonicalization"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.