See how sigstore compares to other vendors in security performance
Impact What kind of vulnerability is it? Who is impacted?
A verifier configured with WithTransparencyLog(N>1) or WithSignedCertificateTimestamps(N>1) expected defense-in-depth against the compromise of a single log instance. However, threshold counting counted verified witnesses per-entry or per-validation-path rather than per-log-authority.
As a result, a single compromised transparency log could forge multiple entries with different indices, and a single compromised CT log could verify multiple times (either across multiple certificate chains or via multiple embedded SCTs), fully satisfying the multi-log threshold requirements and defeating the multi-log policy.
Note that this does not affect Cosign, as Cosign sets a threshold of 1.
Patches Has the problem been patched? What versions should users upgrade to?
Upgrade to v1.1.5.
Workarounds Is there a way for users to fix or remediate the vulnerability without upgrading?
There is no workaround, beyond relying on trusted logs.
Description
cosign verify-blob-attestation may erroneously report a "Verified OK" result for attestations with malformed payloads or mismatched predicate types. For old-format bundles and detached signatures, this was due to a logic flaw in the error handling of the predicate type validation. For new-format bundles, the predicate type validation was bypassed completely.
Impact
When cosign verify-blob-attestation is used without --check-claims set to true, an attestation that has a valid signature but a malformed or unparsable payload would be incorrectly validated. Additionally, systems relying on --type <predicate type> to reject attestations with mismatched types would be lead to trust the unexpected attestation type.
Patches
v3.0.6, v2.6.3
Workarounds
Always set --check-claims=true for attestation verification.
Summary
Sigstore::Verifier#verify does not propagate the VerificationFailure returned by verifyintoto when the artifact digest does not match the digest in the in-toto attestation subject. As a result, verification of DSSE bundles containing in-toto statements returns VerificationSuccess regardless of whether the artifact matches the attested subject.
Details
In lib/sigstore/verifier.rb, the verify method calls verifyintoto (line 176) without capturing or checking its return value:
verifyintoto(input, intoto)
When verifyintoto detects a digest mismatch, it returns a VerificationFailure object. Because the caller discards this return value, execution unconditionally falls through to return VerificationSuccess. This is the only verification sub-check in the method (out of 12) whose failure is not propagated.
The messagesignature code path is not affected.
Impact
An attacker who possesses a valid signed DSSE bundle containing an in-toto attestation for artifact A can present it as a valid attestation for a different artifact B. All other verification checks (DSSE envelope signature, certificate chain, Rekor inclusion, SCTs, policy) pass because they are independent of the artifact content. Only the in-toto subject digest check detects the mismatch, and its result is discarded.
This allows an attacker to bypass artifact-to-attestation binding for any consumer that relies on Sigstore::Verifier#verify to validate DSSE/in-toto bundles.
Workarounds
None. Consumers cannot work around this without patching the library.
Summary
When verifying artifact signatures using a certificate, Cosign first verifies the certificate chain using the leaf certificate's "not before" timestamp and later checks expiry of the leaf certificate using either a signed timestamp provided by the Rekor transparency log or from a timestamp authority, or using the current time. The root and all issuing certificates are assumed to be valid during the leaf certificate's validity. An issuing certificate with a validity that expires before the leaf certificate will be considered valid during verification even if the provided timestamp would mean the issuing certificate should be considered expired.
Impact
No impact to users of the public Sigstore infrastructure. This may affect private deployments with customized PKIs. In practice, this is unlikely to occur as CAs should not be issuing certificates that outlive the validity of the CA and its parents.
Workarounds
Upgrade to the latest release, or verify the certificate chain out of band.
Example to Reproduce
Root CA certificate is valid from 12pm-2pm Intermediate CA certificate is valid from 12:30pm-1:30pm Leaf certificate is valid from 1pm-3pm - Note that this is unlikely to happen in practice, as a CA shouldn't issue a certificate that would be valid after the issuing CA certificate expires Signature generated at 2:30pm with a signed timestamp During verification, the leaf certificate's not before time (1pm) is used to verify the chain - 1pm is in the validity windows for the root and intermediate CA certificates The timestamp's time is checked to be in the validity window of only the leaf certificate - 2:30pm is in the validity window for the leaf Even though the root and intermediate would be expired at 2:30pm, verification succeeds
Impact
A Cosign bundle can be crafted to successfully verify an artifact even if the embedded Rekor entry does not reference the artifact's digest, signature or public key. When verifying a Rekor entry, Cosign verifies the Rekor entry signature, and also compares the artifact's digest, the user's public key from either a Fulcio certificate or provided by the user, and the artifact signature to the Rekor entry contents. Without these comparisons, Cosign would accept any response from Rekor as valid. A malicious actor that has compromised a user's identity or signing key could construct a valid Cosign bundle by including any arbitrary Rekor entry, thus preventing the user from being able to audit the signing event.
This vulnerability only affects users that provide a trusted root via --trusted-root or when fetched automatically from a TUF repository, when no trusted key material is provided via SIGSTOREREKORPUBLICKEY. When using the default flag values in Cosign v3 to sign and verify (--use-signing-config=true and --new-bundle-format=true for signing, --new-bundle-format=true for verification), users are unaffected. Cosign v2 users are affected using the default flag values.
This issue had previously been fixed in https://github.com/sigstore/cosign/security/advisories/GHSA-8gw7-4j42-w388 but recent refactoring caused a regression. We have added testing to prevent a future regression.
Steps to Reproduce
echo blob > /tmp/blob cosign sign-blob -y --new-bundle-format=false --bundle /tmp/bundle.1 --use-signing-config=false /tmp/blob cosign sign-blob -y --new-bundle-format=false --bundle /tmp/bundle.2 --use-signing-config=false /tmp/blob jq ".rekorBundle |= $(jq .rekorBundle /tmp/bundle.2)" /tmp/bundle.1 > /tmp/bundle.3 cosign verify-blob --bundle /tmp/bundle.3 --certificate-identity-regexp='.' --certificate-oidc-issuer-regexp='.' /tmp/blob
Patches
Upgrade to Cosign v2.6.2 or Cosign v3.0.4. This does not affect Cosign v1.
Workarounds
You can provide trusted key material via a set of flags under certain conditions. The simplest fix is to upgrade to the latest Cosign v2 or v3 release.
Note that the example below works for cosign verify, cosign verify-blob, cosign verify-blob-attestation, and cosign verify-attestation.
SIGSTOREREKORPUBLICKEY=<path to Rekor pub key> cosign verify-blob --use-signing-config=false --new-bundle-format=false --bundle=<path to bundle> <artifact>
Impact
Excessive memory allocation
Function api.ParseJSONRequest currently splits (via a call to strings.Split) an optionally-provided OID (which is untrusted data) on periods. Similarly, function api.getContentType splits the Content-Type header (which is also untrusted data) on an application string.
As a result, in the face of a malicious request with either an excessively long OID in the payload containing many period characters or a malformed Content-Type header, a call to api.ParseJSONRequest or api.getContentType incurs allocations of O(n) bytes (where n stands for the length of the function's argument). Relevant weakness: CWE-405: Asymmetric Resource Consumption (Amplification)
Patches
Upgrade to v2.0.3.
Workarounds
There are no workarounds with the service itself. If the service is behind a load balancer, configure the load balancer to reject excessively large requests.
Impact
sigstore-go is susceptible to a denial of service attack when a verifier is provided a maliciously crafted Sigstore Bundle containing large amounts of verifiable data, in the form of signed transparency log entries, RFC 3161 timestamps, and attestation subjects. The verification of these data structures is computationally expensive. This can be used to consume excessive CPU resources, leading to a denial of service attack. TUF's security model labels this type of vulnerability an "Endless data attack," and can lead to verification failing to complete and disrupting services that rely on sigstore-go for verification.
The vulnerable loops are in the verification functions in the package github.com/sigstore/sigstore-go/pkg/verify. The first is the DSSE envelope verification loop in verifyEnvelopeWithArtifact, which decodes all the digests in an attestation can be found here:
https://github.com/sigstore/sigstore-go/blob/725e508ed4933e6f5b5206e32af4bbe76f587b54/pkg/verify/signature.go#L183-L193
The next loop is in the VerifyArtifactTransparencyLog function, which verifies all the signed entries in a bundle:
https://github.com/sigstore/sigstore-go/blob/725e508ed4933e6f5b5206e32af4bbe76f587b54/pkg/verify/tlog.go#L74-L178
The next loop is the VerifyTimestampAuthority function, which verifies all the RFC 3161 timestamps in a bundle:
https://github.com/sigstore/sigstore-go/blob/725e508ed4933e6f5b5206e32af4bbe76f587b54/pkg/verify/tsa.go#L59-L68
Patches
This vulnerability is addressed with sigstore-go 0.6.1, which adds hard limits to the number of verifiable data structures that can be processed in a bundle. Verification will fail if a bundle has data that exceeds these limits. The limits are:
- 32 signed transparency log entries - 32 RFC 3161 timestamps - 1024 attestation subjects - 32 digests per attestation subject
These limits are intended to be high enough to accommodate the vast majority of use cases, while preventing the verification of maliciously crafted bundles that contain large amounts of verifiable data.
Workarounds
The best way to mitigate the risk is to upgrade to sigstore-go 0.6.1 or later. Users who are vulnerable but unable to quickly upgrade may consider adding manual bundle validation to enforce limits similar to those in the referenced patch prior to calling sigstore-go's verification functions.
Cosign provides code signing and transparency for containers and binaries. Prior to version 2.2.4, maliciously-crafted software artifacts can cause denial of service of the machine running Cosign thereby impacting all services on the machine. The root cause is that Cosign creates slices based on the number of signatures, manifests or attestations in untrusted artifacts. As such, the untrusted artifact can control the amount of memory that Cosign allocates. The exact issue is Cosign allocates excessive memory on the lines that creates a slice of the same length as the manifests. Version 2.2.4 contains a patch for the vulnerability.
Summary A remote image with a malicious attachment can cause denial of service of the host machine running Cosign. This can impact other services on the machine that rely on having memory available such as a Redis database which can result in data loss. It can also impact the availability of other services on the machine that will not be available for the duration of the machine denial.
Details The root cause of this issue is that Cosign reads the attachment from a remote image entirely into memory without checking the size of the attachment first. As such, a large attachment can make Cosign read a large attachment into memory; If the attachments size is larger than the machine has memory available, the machine will be denied of service. The Go runtime will make a SIGKILL after a few seconds of system-wide denial.
The root cause is that Cosign reads the contents of the attachments entirely into memory on line 238 below:
https://github.com/sigstore/cosign/blob/9bc3ee309bf35d2f6e17f5d23f231a3d8bf580bc/pkg/oci/remote/remote.go#L228-L239
...and prior to that, neither Cosign nor go-containerregistry checks the size of the attachment and enforces a max cap. In the case of a remote layer of f attached, go-containerregistry will invoke this API:
https://github.com/google/go-containerregistry/blob/a0658aa1d0cc7a7f1bcc4a3af9155335b6943f40/pkg/v1/remote/layer.go#L36-L40 golang func (rl remoteLayer) Compressed() (io.ReadCloser, error) { // We don't want to log binary layers -- this can break terminals. ctx := redact.NewContext(rl.ctx, "omitting binary blobs from logs") return rl.fetcher.fetchBlob(ctx, verify.SizeUnknown, rl.digest) }
Notice that the second argument to rl.fetcher.fetchBlob is verify.SizeUnknown which results in not using the io.LimitReader in verify.ReadCloser: https://github.com/google/go-containerregistry/blob/a0658aa1d0cc7a7f1bcc4a3af9155335b6943f40/internal/verify/verify.go#L82-L100 golang func ReadCloser(r io.ReadCloser, size int64, h v1.Hash) (io.ReadCloser, error) { w, err := v1.Hasher(h.Algorithm) if err != nil { return nil, err } r2 := io.TeeReader(r, w) // pass all writes to the hasher. if size != SizeUnknown { r2 = io.LimitReader(r2, size) // if we know the size, limit to that size. } return &and.ReadCloser{ Reader: &verifyReader{ inner: r2, hasher: w, expected: h, wantSize: size, }, CloseFunc: r.Close, }, nil }
Impact This issue can allow a supply-chain escalation from a compromised registry to the Cosign user: If an attacher has compromised a registry or the account of an image vendor, they can include a malicious attachment and hurt the image consumer.
Remediation Update to the latest version of Cosign, which limits the number of attachments. An environment variable can override this value.
Impact
In certain versions of gitsign, Rekor public keys were fetched via the Rekor API, instead of through the local TUF client. If the upstream Rekor server happened to be compromised, gitsign clients could potentially be tricked into trusting incorrect signatures.
There is no known compromise the default public good instance (rekor.sigstore.dev) - anyone using this instance is unlikely to be affected.
Patches
This was fixed in v0.8.0 via https://github.com/sigstore/gitsign/pull/399
Workarounds
n/a
References Are there any links users can visit to find out more?
https://docs.sigstore.dev/about/threat-model/#sigstore-threat-model
Summary Cosign is susceptible to a denial of service by an attacker controlled registry. An attacker who controls a remote registry can return a high number of attestations and/or signatures to Cosign and cause Cosign to enter a long loop resulting in an endless data attack. The root cause is that Cosign loops through all attestations fetched from the remote registry in pkg/cosign.FetchAttestations.
The attacker needs to compromise the registry or make a request to a registry they control. When doing so, the attacker must return a high number of attestations in the response to Cosign. The result will be that the attacker can cause Cosign to go into a long or infinite loop that will prevent other users from verifying their data. In Kyvernos case, an attacker whose privileges are limited to making requests to the cluster can make a request with an image reference to their own registry, trigger the infinite loop and deny other users from completing their admission requests. Alternatively, the attacker can obtain control of the registry used by an organization and return a high number of attestations instead the expected number of attestations.
The vulnerable loop in Cosign starts on line 154 below: https://github.com/sigstore/cosign/blob/004443228442850fb28f248fd59765afad99b6df/pkg/cosign/fetch.go#L135-L196
The l slice is controllable by an attacker who controls the remote registry.
Many cloud-native projects consider the remote registry to be untrusted, including Crossplane, Notary and Kyverno. We consider the same to be the case for Cosign, since users are not in control of whether the registry returns the expected data.
TUF's security model labels this type of vulnerability an "Endless data attack", but an attacker could use this as a type of rollback attack, in case the user attempts to deploy a patched version of a vulnerable image; The attacker could prevent this upgrade by causing Cosign to get stuck in an infinite loop and never complete.
Mitigation The issue can be mitigated rather simply by setting a limit to the limit of attestations that Cosign will loop through. The limit does not need to be high to be within the vast majority of use cases and still prevent the endless data attack.
Summary
A number of vulnerabilities have been found in cosign verify-blob, where Cosign would successfully verify an artifact when verification should have failed.
Vulnerability 1: Bundle mismatch causes invalid verification.
Summary A cosign bundle can be crafted to successfully verify a blob even if the embedded rekorBundle does not reference the given signature.
Details Cosign supports "bundles" which intend to allow offline verification of the signature and rekor inclusion. By using the --bundle flag in cosign sign-blob, cosign will create a JSON file called a "bundle". These bundles include three fields: base64Signature, cert, and rekorBundle. The desired behavior is that the verification of these bundles would:
- verify the provided blob using the included signature and certificate - verify the rekorBundle SET - verify the rekorBundle payload references the given artifact.
It appears that step three is not being performed, allowing "any old rekorBundle" to pass validation, even if the rekorBundle payload does not reference the provided blob or the certificate and signature in the rekorBundle do not match those at the top level.
Steps to reproduce Enable keyless signing:
export COSIGNEXPERIMENTAL=1 Create two random blobs: dd bs=1 count=50 </dev/urandom >blob1 dd bs=1 count=50 </dev/urandom >blob2 Sign each blob: cosign sign-blob blob1 --bundle bundle1 cosign sign-blob blob2 --bundle bundle2 Create a falsified bundle including the base64Signature and cert fields from bundle1 and the rekorBundle from bundle2: jq --slurpfile bundle2 bundle2 '.rekorBundle = $bundle2[0].rekorBundle' bundle1 > invalidBundle Now, the falsified bundle can be used to verify blob1: $ cosign verify-blob blob1 --bundle invalidBundle tlog entry verified offline Verified OK
Patches
Users should update to the latest version of Cosign, 1.12.0.
Workaround
If you extract the signature and certificate from the bundle, you may use it for verification as follows and avoid using an invalid bundle: $ cosign verify-blob blob1 --signature $(jq -r '.base64Signature' bundle1) --certificate $(jq -r '.cert' bundle1)
Note that this will make a network call to Rekor to fetch the Rekor entry. However, you may then be subject to Vulnerability 4.
Vulnerability 2: Certificate Identities are not checked in some cases
Summary
When providing identity flags, the email and issuer of a certificate is not checked when verifying a Rekor bundle, and the GitHub Actions identity is never checked.
Details
Users who provide an offline Rekor bundle (--bundle) when verifying a blob using cosign verify-blob and include flags that check identity such as --certificate-email and --certificate-oidc-issuer are impacted. Additionally, users who provide the GitHub Actions verification flags such as --certificate-github-workflow-name when running cosign verify-blob without a bundle, key reference, or certificate are impacted.
When providing these flags, Cosign ignored their values. If a certificate's identity did not match the provided flags, Cosign would still successfully verify the blob.
Patches
Users should update to the latest version of Cosign, 1.12.0.
Workarounds
There are no workarounds, users should update.
Vulnerability 3: Invalid Rekor bundle without the experimental flag will result in successful verification
Summary
Providing an invalid Rekor bundle without the experimental flag results in a successful verification.
Details
Users who provide an offline Rekor bundle (--bundle) that was invalid (invalid signed entry timestamp, expired certificate, or malformed) when verifying a blob with cosign verify-blob and do not set the COSIGNEXPERIMENTAL=1 flag are impacted.
When an invalid bundle was provided, Cosign would fallback to checking Rekor log inclusion by requesting proof of inclusion from the log. However, without the COSIGNEXPERIMENTAL flag, Cosign would exit early and successfully verify the blob.
Patches
Users should update to the latest version of Cosign, 1.12.0.
Workarounds
There are no workarounds, users should update.
Vulnerability 4: Invalid transparency log entry will result in successful verification
Summary
An invalid transparency log entry will result in immediate success for verification.
Details
Users who provide a signature and certificate to verify-blob will fetch the associated Rekor entry for verification. If the returned entry was invalid (invalid signed entry timestamp, invalid inclusion proof, malformed entry with missing verification), then cosign exits early and succeeds unconditionally.
Patches
Users should update to the latest version of Cosign, 1.12.0.
Workarounds
There are no workarounds, users should update.
For more information If you have any questions or comments about this advisory: Open an issue in cosign Send us a message on Slack.
PolicyController is a utility used to enforce supply chain policy in Kubernetes clusters. In versions prior to 0.2.1 PolicyController will report a false positive, resulting in an admission when it should not be admitted when there is at least one attestation with a valid signature and there are NO attestations of the type being verified (--type defaults to "custom"). An example image that can be used to test this is ghcr.io/distroless/static@sha256:dd7614b5a12bc4d617b223c588b4e0c833402b8f4991fb5702ea83afad1986e2. Users should upgrade to version 0.2.1 to resolve this issue. There are no workarounds for users unable to upgrade.
cosign is a container signing and verification utility. In versions prior to 1.10.1 cosign can report a false positive if any attestation exists. cosign verify-attestation used with the --type flag will report a false positive verification when there is at least one attestation with a valid signature and there are NO attestations of the type being verified (--type defaults to "custom"). This can happen when signing with a standard keypair and with "keyless" signing with Fulcio. This vulnerability can be reproduced with the distroless.dev/static@sha256:dd7614b5a12bc4d617b223c588b4e0c833402b8f4991fb5702ea83afad1986e2 image. This image has a vuln attestation but not an spdx attestation. However, if you run cosign verify-attestation --type=spdx on this image, it incorrectly succeeds. This issue has been addressed in version 1.10.1 of cosign. Users are advised to upgrade. There are no known workarounds for this issue.
Cosign provides container signing, verification, and storage in an OCI registry for the sigstore project. Prior to version 1.5.2, Cosign can be manipulated to claim that an entry for a signature exists in the Rekor transparency log even if it doesn't. This requires the attacker to have pull and push permissions for the signature in OCI. This can happen with both standard signing with a keypair and "keyless signing" with Fulcio. If an attacker has access to the signature in OCI, they can manipulate cosign into believing the entry was stored in Rekor even though it wasn't. The vulnerability has been patched in v1.5.2 of Cosign. The signature in the signedEntryTimestamp provided by Rekor is now compared to the signature that is being verified. If these don't match, then an error is returned. If a valid bundle is copied to a different signature, verification should fail. Cosign output now only informs the user that certificates were verified if a certificate was in fact verified. There is currently no known workaround.