malformed proposed intoto v0.0.2 entries can cause a panic in Rekor
Description
Rekor's goals are to provide an immutable tamper resistant ledger of metadata generated within a software projects supply chain. A malformed proposed entry of the intoto/v0.0.2 type can cause a panic on a thread within the Rekor process. The thread is recovered so the client receives a 500 error message and service still continues, so the availability impact of this is minimal. This has been fixed in v1.2.0 of Rekor. Users are advised to upgrade. There are no known workarounds for this vulnerability.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/sigstore/rekorGo | < 1.2.0 | 1.2.0 |
Affected products
1Patches
1140c5add1051Merge pull request from GHSA-frqx-jfcm-6jjr
7 files changed · +128 −26
pkg/generated/models/intoto_v002_schema.go+35 −2 modified@@ -450,16 +450,49 @@ type IntotoV002SchemaContentEnvelopeSignaturesItems0 struct { Keyid string `json:"keyid,omitempty"` // public key that corresponds to this signature + // Required: true // Format: byte - PublicKey strfmt.Base64 `json:"publicKey,omitempty"` + PublicKey *strfmt.Base64 `json:"publicKey"` // signature of the payload + // Required: true // Format: byte - Sig strfmt.Base64 `json:"sig,omitempty"` + Sig *strfmt.Base64 `json:"sig"` } // Validate validates this intoto v002 schema content envelope signatures items0 func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePublicKey(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSig(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) validatePublicKey(formats strfmt.Registry) error { + + if err := validate.Required("publicKey", "body", m.PublicKey); err != nil { + return err + } + + return nil +} + +func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) validateSig(formats strfmt.Registry) error { + + if err := validate.Required("sig", "body", m.Sig); err != nil { + return err + } + return nil }
pkg/generated/restapi/embedded_spec.go+4 −0 modified@@ -2167,6 +2167,10 @@ func init() { "IntotoV002SchemaContentEnvelopeSignaturesItems0": { "description": "a signature of the envelope's payload along with the public key for the signature", "type": "object", + "required": [ + "sig", + "publicKey" + ], "properties": { "keyid": { "description": "optional id of the key used to create the signature",
pkg/types/dsse/v0.0.1/entry.go+7 −0 modified@@ -75,6 +75,9 @@ func (v V001Entry) IndexKeys() ([]string, error) { var result []string for _, sig := range v.DSSEObj.Signatures { + if sig == nil || sig.Verifier == nil { + return result, errors.New("missing or malformed public key") + } keyObj, err := x509.NewPublicKey(bytes.NewReader(*sig.Verifier)) if err != nil { return result, err @@ -202,6 +205,10 @@ func (v *V001Entry) Unmarshal(pe models.ProposedEntry) error { allPubKeyBytes := make([][]byte, 0) for _, publicKey := range dsseObj.ProposedContent.Verifiers { + if publicKey == nil { + return errors.New("an invalid null verifier was provided in ProposedContent") + } + allPubKeyBytes = append(allPubKeyBytes, publicKey) }
pkg/types/dsse/v0.0.1/entry_test.go+14 −0 modified@@ -158,6 +158,9 @@ func TestV001Entry_Unmarshal(t *testing.T) { }, } + validEnv := envelope(t, key, []byte("payload")) + validEnvBytes, _ := json.Marshal(validEnv) + validPayload := "hellothispayloadisvalid" tests := []struct { @@ -218,6 +221,17 @@ func TestV001Entry_Unmarshal(t *testing.T) { }, wantErr: false, }, + { + env: validEnv, + name: "null verifier in array", + it: &models.DSSEV001Schema{ + ProposedContent: &models.DSSEV001SchemaProposedContent{ + Envelope: swag.String(string(validEnvBytes)), + Verifiers: []strfmt.Base64{pub, nil}, + }, + }, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {
pkg/types/intoto/v0.0.2/entry.go+21 −9 modified@@ -32,6 +32,7 @@ import ( "github.com/in-toto/in-toto-golang/in_toto" "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/spf13/viper" + "golang.org/x/exp/slices" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" @@ -78,7 +79,10 @@ func (v V002Entry) IndexKeys() ([]string, error) { } for _, sig := range v.IntotoObj.Content.Envelope.Signatures { - keyObj, err := x509.NewPublicKey(bytes.NewReader(sig.PublicKey)) + if sig == nil || sig.PublicKey == nil { + return result, errors.New("malformed or missing signature") + } + keyObj, err := x509.NewPublicKey(bytes.NewReader(*sig.PublicKey)) if err != nil { return result, err } @@ -182,13 +186,17 @@ func (v *V002Entry) Unmarshal(pe models.ProposedEntry) error { } allPubKeyBytes := make([][]byte, 0) - for _, sig := range v.IntotoObj.Content.Envelope.Signatures { + for i, sig := range v.IntotoObj.Content.Envelope.Signatures { + if sig == nil { + v.IntotoObj.Content.Envelope.Signatures = slices.Delete(v.IntotoObj.Content.Envelope.Signatures, i, i) + continue + } env.Signatures = append(env.Signatures, dsse.Signature{ KeyID: sig.Keyid, - Sig: string(sig.Sig), + Sig: string(*sig.Sig), }) - allPubKeyBytes = append(allPubKeyBytes, sig.PublicKey) + allPubKeyBytes = append(allPubKeyBytes, *sig.PublicKey) } if _, err := verifyEnvelope(allPubKeyBytes, env); err != nil { @@ -381,10 +389,11 @@ func (v V002Entry) CreateFromArtifactProperties(_ context.Context, props types.A } keyBytes := strfmt.Base64(canonKey) + sigBytes := strfmt.Base64([]byte(sig.Sig)) re.IntotoObj.Content.Envelope.Signatures = append(re.IntotoObj.Content.Envelope.Signatures, &models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ Keyid: sig.KeyID, - Sig: strfmt.Base64([]byte(sig.Sig)), - PublicKey: keyBytes, + Sig: &sigBytes, + PublicKey: &keyBytes, }) } @@ -458,7 +467,7 @@ func (v V002Entry) Verifier() (pki.PublicKey, error) { return nil, errors.New("no signatures found on intoto entry") } - return x509.NewPublicKey(bytes.NewReader(v.IntotoObj.Content.Envelope.Signatures[0].PublicKey)) + return x509.NewPublicKey(bytes.NewReader(*v.IntotoObj.Content.Envelope.Signatures[0].PublicKey)) } func (v V002Entry) Insertable() (bool, error) { @@ -480,10 +489,13 @@ func (v V002Entry) Insertable() (bool, error) { return false, errors.New("missing signatures content") } for _, sig := range v.IntotoObj.Content.Envelope.Signatures { - if len(sig.Sig) == 0 { + if sig == nil { + return false, errors.New("missing signature entry") + } + if sig.Sig == nil || len(*sig.Sig) == 0 { return false, errors.New("missing signature content") } - if len(sig.PublicKey) == 0 { + if sig.PublicKey == nil || len(*sig.PublicKey) == 0 { return false, errors.New("missing publicKey content") } }
pkg/types/intoto/v0.0.2/entry_test.go+45 −14 modified@@ -111,10 +111,12 @@ func createRekorEnvelope(dsseEnv *dsse.Envelope, pub [][]byte) *models.IntotoV00 env.PayloadType = &dsseEnv.PayloadType for i, sig := range dsseEnv.Signatures { + keyBytes := strfmt.Base64(pub[i]) + sigBytes := strfmt.Base64([]byte(sig.Sig)) env.Signatures = append(env.Signatures, &models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ Keyid: sig.KeyID, - Sig: strfmt.Base64([]byte(sig.Sig)), - PublicKey: strfmt.Base64(pub[i]), + Sig: &sigBytes, + PublicKey: &keyBytes, }) } @@ -172,6 +174,8 @@ func TestV002Entry_Unmarshal(t *testing.T) { } validPayload := "hellothispayloadisvalid" + keyBytes := strfmt.Base64("key") + sigBytes := strfmt.Base64("sig") tests := []struct { env *dsse.Envelope @@ -273,6 +277,31 @@ func TestV002Entry_Unmarshal(t *testing.T) { wantErr: false, wantVerifierErr: false, }, + { + env: envelope(t, key, []byte(validPayload)), + name: "null array entry", + it: &models.IntotoV002Schema{ + Content: &models.IntotoV002SchemaContent{ + Envelope: &models.IntotoV002SchemaContentEnvelope{ + Payload: strfmt.Base64("cGF5bG9hZAo="), + PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + PublicKey: &keyBytes, + Sig: &sigBytes, + }, + nil, + }, + }, + Hash: &models.IntotoV002SchemaContentHash{ + Algorithm: swag.String(models.IntotoV002SchemaContentHashAlgorithmSha256), + Value: swag.String(envelopeHash(t, envelope(t, key, []byte(validPayload)))), + }, + }, + }, + wantErr: true, + wantVerifierErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -295,7 +324,7 @@ func TestV002Entry_Unmarshal(t *testing.T) { want := []string{} for _, sig := range v.IntotoObj.Content.Envelope.Signatures { - keyHash := sha256.Sum256(sig.PublicKey) + keyHash := sha256.Sum256(*sig.PublicKey) want = append(want, "sha256:"+hex.EncodeToString(keyHash[:])) } decodedPayload, err := base64.StdEncoding.DecodeString(tt.env.Payload) @@ -483,7 +512,7 @@ func TestV002Entry_IndexKeys(t *testing.T) { } want := []string{} for _, sig := range v.IntotoObj.Content.Envelope.Signatures { - keyHash := sha256.Sum256(sig.PublicKey) + keyHash := sha256.Sum256(*sig.PublicKey) want = append(want, "sha256:"+hex.EncodeToString(keyHash[:])) } @@ -513,6 +542,8 @@ func TestInsertable(t *testing.T) { } env := envelope(t, key, []byte("payload")) + keyBytes := strfmt.Base64([]byte("key")) + sigBytes := strfmt.Base64([]byte("sig")) testCases := []TestCase{ { @@ -525,8 +556,8 @@ func TestInsertable(t *testing.T) { PayloadType: swag.String("payloadType"), Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ { - PublicKey: strfmt.Base64([]byte("key")), - Sig: strfmt.Base64([]byte("sig")), + PublicKey: &keyBytes, + Sig: &sigBytes, }, }, }, @@ -546,8 +577,8 @@ func TestInsertable(t *testing.T) { PayloadType: swag.String("payloadType"), Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ { - PublicKey: strfmt.Base64([]byte("key")), - Sig: strfmt.Base64([]byte("sig")), + PublicKey: &keyBytes, + Sig: &sigBytes, }, }, }, @@ -567,7 +598,7 @@ func TestInsertable(t *testing.T) { PayloadType: swag.String("payloadType"), Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ { - PublicKey: strfmt.Base64([]byte("key")), + PublicKey: &keyBytes, //Sig: strfmt.Base64([]byte("sig")), }, }, @@ -589,7 +620,7 @@ func TestInsertable(t *testing.T) { Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ { //PublicKey: strfmt.Base64([]byte("key")), - Sig: strfmt.Base64([]byte("sig")), + Sig: &sigBytes, }, }, }, @@ -633,8 +664,8 @@ func TestInsertable(t *testing.T) { //PayloadType: swag.String("payloadType"), Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ { - PublicKey: strfmt.Base64([]byte("key")), - Sig: strfmt.Base64([]byte("sig")), + PublicKey: &keyBytes, + Sig: &sigBytes, }, }, }, @@ -654,8 +685,8 @@ func TestInsertable(t *testing.T) { PayloadType: swag.String("payloadType"), Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ { - PublicKey: strfmt.Base64([]byte("key")), - Sig: strfmt.Base64([]byte("sig")), + PublicKey: &keyBytes, + Sig: &sigBytes, }, }, },
pkg/types/intoto/v0.0.2/intoto_v0_0_2_schema.json+2 −1 modified@@ -44,7 +44,8 @@ "type": "string", "format": "byte" } - } + }, + "required": ["sig", "publicKey"] } } },
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/advisories/GHSA-frqx-jfcm-6jjrghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-33199ghsaADVISORY
- github.com/sigstore/rekor/commit/140c5add105179e5ffd9e3e114fd1b6b93aebbd4ghsax_refsource_MISCWEB
- github.com/sigstore/rekor/security/advisories/GHSA-frqx-jfcm-6jjrghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.