VYPR
Medium severityNVD Advisory· Published Feb 11, 2025· Updated Apr 15, 2026

CVE-2025-24976

CVE-2025-24976

Description

Distribution is a toolkit to pack, ship, store, and deliver container content. Systems running registry versions 3.0.0-beta.1 through 3.0.0-rc.2 with token authentication enabled may be vulnerable to an issue in which token authentication allows an attacker to inject an untrusted signing key in a JSON web token (JWT). The issue lies in how the JSON web key (JWK) verification is performed. When a JWT contains a JWK header without a certificate chain, the code only checks if the KeyID (kid) matches one of the trusted keys, but doesn't verify that the actual key material matches. A fix for the issue is available at commit 5ea9aa028db65ca5665f6af2c20ecf9dc34e5fcd and expected to be a part of version 3.0.0-rc.3. There is no way to work around this issue without patching if the system requires token authentication.

Patches

1
f4a500caf681

Fix registry token authentication bug

https://github.com/distribution/distributionMilos GajdosFeb 1, 2025via ghsa
2 files changed · +57 2
  • registry/auth/token/token.go+3 2 modified
    @@ -219,11 +219,12 @@ func verifyJWK(header jose.Header, verifyOpts VerifyOptions) (signingKey crypto.
     	// Check to see if the key includes a certificate chain.
     	if len(jwk.Certificates) == 0 {
     		// The JWK should be one of the trusted root keys.
    -		if _, trusted := verifyOpts.TrustedKeys[jwk.KeyID]; !trusted {
    +		trustedKey, trusted := verifyOpts.TrustedKeys[jwk.KeyID]
    +		if !trusted {
     			return nil, errors.New("untrusted JWK with no certificate chain")
     		}
     		// The JWK is one of the trusted keys.
    -		return
    +		return trustedKey, nil
     	}
     
     	opts := x509.VerifyOptions{
    
  • registry/auth/token/token_test.go+54 0 modified
    @@ -646,3 +646,57 @@ func TestNewAccessControllerPemBlock(t *testing.T) {
     		t.Fatal("accessController has the wrong number of certificates")
     	}
     }
    +
    +// This test makes sure the untrusted key can not be used in token verification.
    +func TestVerifyJWKWithTrustedKey(t *testing.T) {
    +	// Generate a test key pair
    +	privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    +	if err != nil {
    +		t.Fatal(err)
    +	}
    +	pubKey := privKey.Public()
    +
    +	// Create a JWK with no certificates
    +	jwk := &jose.JSONWebKey{
    +		Key:       privKey,
    +		KeyID:     "test-key-id",
    +		Use:       "sig",
    +		Algorithm: string(jose.ES256),
    +	}
    +
    +	// Create verify options with our public key as trusted
    +	verifyOpts := VerifyOptions{
    +		TrustedKeys: map[string]crypto.PublicKey{
    +			"test-key-id": pubKey,
    +		},
    +	}
    +
    +	// Create test header
    +	header := jose.Header{
    +		JSONWebKey: jwk,
    +	}
    +
    +	// Test the verifyJWK function
    +	returnedKey, err := verifyJWK(header, verifyOpts)
    +	if err != nil {
    +		t.Fatalf("Expected no error, got: %v", err)
    +	}
    +
    +	// Verify the returned key matches our trusted key
    +	if returnedKey != pubKey {
    +		t.Error("Returned key does not match the trusted key")
    +	}
    +
    +	// Test with untrusted key
    +	verifyOpts.TrustedKeys = map[string]crypto.PublicKey{
    +		"different-key-id": pubKey,
    +	}
    +
    +	_, err = verifyJWK(header, verifyOpts)
    +	if err == nil {
    +		t.Error("Expected error for untrusted key, got none")
    +	}
    +	if err.Error() != "untrusted JWK with no certificate chain" {
    +		t.Errorf("Expected 'untrusted JWK with no certificate chain' error, got: %v", err)
    +	}
    +}
    

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

News mentions

0

No linked articles in our index yet.