{"record":{"id":"c922685f6d31420f","repo":"netbirdio/netbird","slug":"artifact-key-verification-failed-w","errorCode":null,"errorMessage":"artifact key verification failed: %w","messagePattern":"artifact key verification failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"client/cmd/signer/artifactsign.go","lineNumber":250,"sourceCode":"\n\t// Read optional revocation list\n\tvar revocationList *reposign.RevocationList\n\tif revocationFile != \"\" {\n\t\trevData, err := os.ReadFile(revocationFile)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"read revocation file: %w\", err)\n\t\t}\n\n\t\trevocationList, err = reposign.ParseRevocationList(revData)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse revocation list: %w\", err)\n\t\t}\n\t}\n\n\t// Validate artifact key(s)\n\tvalidKeys, err := reposign.ValidateArtifactKeys(rootPublicKeys, artifactKeyData, *signature, revocationList)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"artifact key verification failed: %w\", err)\n\t}\n\n\tcmd.Println(\"✅ Artifact key(s) verified successfully\")\n\tcmd.Printf(\"Signed by root key: %s\\n\", signature.KeyID)\n\tcmd.Printf(\"Signature timestamp: %s\\n\", signature.Timestamp.Format(\"2006-01-02 15:04:05 MST\"))\n\tcmd.Printf(\"\\nValid artifact keys (%d):\\n\", len(validKeys))\n\tfor i, key := range validKeys {\n\t\tcmd.Printf(\"  [%d] Key ID: %s\\n\", i+1, key.Metadata.ID)\n\t\tcmd.Printf(\"      Created: %s\\n\", key.Metadata.CreatedAt.Format(\"2006-01-02 15:04:05 MST\"))\n\t\tif !key.Metadata.ExpiresAt.IsZero() {\n\t\t\tcmd.Printf(\"      Expires: %s\\n\", key.Metadata.ExpiresAt.Format(\"2006-01-02 15:04:05 MST\"))\n\t\t} else {\n\t\t\tcmd.Printf(\"      Expires: Never\\n\")\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/signer/artifactsign.go#L232-L268","documentation":"reposign.ValidateArtifactKeys rejected the root-to-artifact-key chain; this is a security decision in verify-artifact-key. Refusals in reposign/artifact.go:166-219: signature timestamp more than 5 minutes in the future, signature older than 10 years, root signature verification failure (wrong root key, or the key data was modified after signing), PEM bundle parse failure of the artifact keys, and all keys in the bundle being expired or revoked (\"all N artifact keys are revoked\").","triggerScenarios":"Passing the wrong root public key to --root-key-file; the key bundle bytes were modified after the root key signed them; every artifact key in the bundle is past ExpiresAt or listed in the supplied revocation list; verifier clock more than 5 minutes fast; reusing a .sig from a previous bundle rotation.","commonSituations":"Root key rotation where the verifier still holds the old root; artifact keys expired because the release cadence outlived the key lifetime; the supplied revocation file legitimately revoked the leaked key being checked.","solutions":["Confirm --root-key-file is the root public key generation that signed this bundle (check KeyID in the .sig matches a known root key)","Re-fetch the matching artifact-key-pub.pem and artifact-key-pub.pem.sig pair from the key store — they must be the exact pair produced together","Sync the clock (5-minute skew budget) and re-verify","If keys are expired or revoked, generate a new artifact key with generate-artifact-key and publish the new root-signed bundle"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := reposign.ValidateArtifactKeys(rootPublicKeys, artifactKeyData, *signature, revocationList); err != nil {\n    switch {\n    case strings.Contains(err.Error(), \"failed to verify signature of artifact keys\"):\n        log.Fatalf(\"wrong root key or modified bundle: %v\", err)\n    case strings.Contains(err.Error(), \"revoked\"):\n        log.Fatalf(\"all keys revoked/expired: %v\", err)\n    default:\n        log.Fatalf(\"KEY CHAIN VERIFICATION FAILED: %v\", err)\n    }\n}","preventionTips":["Pin the root key generation that signed each bundle; publish bundle and .sig as an atomic pair","Rotate artifact keys before expiry and after any suspected compromise, then extend the revocation list","Sync verifier clocks; the future-timestamp tolerance is 5 minutes"],"tags":["go","crypto","ed25519","verification","release-signing","security"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}