You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If I configure Chains with simplesigning format + sigstore-bundle encoding + transparency enabled, either:
The config should be rejected with an error telling me this combo doesn't work, OR
Signatures should actually verify with cosign verify
Actual Behavior
Everything looks like it works - signing succeeds, Rekor upload succeeds, bundle gets pushed to the registry. But when you try to verify, it blows up:
Error: no matching attestations: failed to verify log inclusion:
transparency log rekor v1 entry is not a dsse_v001 or intoto_v002 entry
The problem is that Chains creates a hashedrekord entry in Rekor (because simplesigning isn't in the IntotoAttestationSet), but then wraps it in a DsseEnvelope bundle. When sigstore-go tries to verify, it sees the DSSE envelope and expects a dsse_v001 or intoto_v002 Rekor entry, but finds hashedrekord instead. Boom.
This creates signatures that literally cannot be verified by anything.
Check the Chains logs - you'll see:
"Created payload of type simplesigning"
"Uploaded entry to https://rekor.sigstore.dev with index XXXXX"
"Using sigstore bundle format for signature storage"
Confirmed against a live sigstore-bundle image signature. For the image signature, Chains builds a bundle whose content type disagrees with what's inside it:
Field
Chains writes
Should be
Bundle content oneof
dsseEnvelope
messageSignature
Payload type
application/vnd.dev.cosign.simplesigning.v1+json
(same)
Rekor entry (if transparency on)
hashedrekord
hashedrekord
A simplesigning payload gets wrapped in a dsseEnvelope content field instead of a messageSignature field. cosign/sigstore-go dispatch on the content type: seeing dsseEnvelope, they expect DSSE — but the payload is simplesigning and (when transparency is on) the Rekor entry is hashedrekord, so verify fails:
transparency log rekor v1 entry is not a dsse_v001 or intoto_v002 entry
This is a labeling bug, not a crypto bug.
Transparency on/off makes no difference
The broken part is the content type, which Chains sets the same way regardless of transparency.enabled. Transparency only changes which error surfaces:
on → the hashedrekord-vs-dsse tlog mismatch above.
off → still a dsseEnvelope wrapping a simplesigning payload, which has no valid DSSE interpretation, so verify still fails.
Either way the bundle is unverifiable. Enabling/disabling transparency does not fix or cause the root issue.
Note on scope: encoding is one global knob
storage.oci.encoding-format applies to the whole OCI backend — image sig and attestation, same run. There's no per-type split. Under sigstore-bundle, the attestation verifies (genuine DSSE + matching dsse/intoto entry) while the image sig fails (simplesigning mislabeled as DSSE). Same encoding, different content type.
Why "just make it a DSSE bundle" isn't the fix
A simplesigning signature is computed over the simplesigning payload, not over DSSE content — there's no valid DSSE form of it. cosign PR #5144 confirms: container signatures stay simplesigning; only attestations get DSSE bundles. The only correct bundle shape for an image sig is messageSignature + hashedrekord.
Proposed approach
Fail fast (short term): reject artifacts.oci.format: simplesigning + storage.oci.encoding-format: sigstore-bundle at config validation, pointing to dsse. - But this is not what we want.
Correct bundle (real fix): for simplesigning, build with Bundle_MessageSignature, not DsseEnvelope, so content type and hashedrekord agree. Attestations keep the DSSE path.
Interim workaround: set storage.oci.encoding-format: dsse. Since the knob is global, both artifacts move to legacy tags — image sig on .sig (cosign verify), attestation on .att (cosign verify-attestation). Both verify.
Activity
anithapriyanatarajan commentedon Oct 8, 2026
Root cause
Confirmed against a live
sigstore-bundleimage signature. For the image signature, Chains builds a bundle whosecontenttype disagrees with what's inside it:contentoneofdsseEnvelopemessageSignatureapplication/vnd.dev.cosign.simplesigning.v1+jsonhashedrekordhashedrekordA
simplesigningpayload gets wrapped in adsseEnvelopecontent field instead of amessageSignaturefield. cosign/sigstore-go dispatch on thecontenttype: seeingdsseEnvelope, they expect DSSE — but the payload is simplesigning and (when transparency is on) the Rekor entry ishashedrekord, so verify fails:This is a labeling bug, not a crypto bug.
Transparency on/off makes no difference
The broken part is the
contenttype, which Chains sets the same way regardless oftransparency.enabled. Transparency only changes which error surfaces:hashedrekord-vs-dssetlog mismatch above.dsseEnvelopewrapping a simplesigning payload, which has no valid DSSE interpretation, so verify still fails.Either way the bundle is unverifiable. Enabling/disabling transparency does not fix or cause the root issue.
Note on scope: encoding is one global knob
storage.oci.encoding-formatapplies to the whole OCI backend — image sig and attestation, same run. There's no per-type split. Undersigstore-bundle, the attestation verifies (genuine DSSE + matchingdsse/intotoentry) while the image sig fails (simplesigning mislabeled as DSSE). Same encoding, differentcontenttype.Why "just make it a DSSE bundle" isn't the fix
A simplesigning signature is computed over the simplesigning payload, not over DSSE content — there's no valid DSSE form of it. cosign PR #5144 confirms: container signatures stay simplesigning; only attestations get DSSE bundles. The only correct bundle shape for an image sig is
messageSignature+hashedrekord.Proposed approach
artifacts.oci.format: simplesigning+storage.oci.encoding-format: sigstore-bundleat config validation, pointing todsse. - But this is not what we want.simplesigning, build withBundle_MessageSignature, notDsseEnvelope, so content type andhashedrekordagree. Attestations keep the DSSE path.Interim workaround: set
storage.oci.encoding-format: dsse. Since the knob is global, both artifacts move to legacy tags — image sig on.sig(cosign verify), attestation on.att(cosign verify-attestation). Both verify.fix(storage): use MessageSignature for OCI signature bundles
fix(storage): use MessageSignature for OCI signature bundles
fix(storage): use MessageSignature for OCI signature bundles
fix(storage): use MessageSignature for OCI signature bundles
fix(storage): use MessageSignature for OCI signature bundles