{"record":{"id":"4f0e449b18c71e9f","repo":"netbirdio/netbird","slug":"artifact-verification-failed-w","errorCode":null,"errorMessage":"artifact verification failed: %w","messagePattern":"artifact verification failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"client/cmd/signer/artifactsign.go","lineNumber":192,"sourceCode":"\tartifactData, err := os.ReadFile(artifactFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read artifact file: %w\", err)\n\t}\n\n\t// Read signature\n\tsigBytes, err := os.ReadFile(signatureFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read signature file: %w\", err)\n\t}\n\n\tsignature, err := reposign.ParseSignature(sigBytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse signature: %w\", err)\n\t}\n\n\t// Validate artifact\n\tif err := reposign.ValidateArtifact([]reposign.PublicKey{publicKey}, artifactData, *signature); err != nil {\n\t\treturn fmt.Errorf(\"artifact verification failed: %w\", err)\n\t}\n\n\tcmd.Println(\"✅ Artifact signature is valid\")\n\tcmd.Printf(\"Artifact: %s\\n\", artifactFile)\n\tcmd.Printf(\"Signed by key: %s\\n\", signature.KeyID)\n\tcmd.Printf(\"Signature timestamp: %s\\n\", signature.Timestamp.Format(\"2006-01-02 15:04:05 MST\"))\n\treturn nil\n}\n\nfunc handleVerifyArtifactKey(cmd *cobra.Command, artifactKeyFile, rootKeyFile, signatureFile, revocationFile string) error {\n\tcmd.Println(\"🔍 Verifying artifact key...\")\n\n\t// Read artifact key data\n\tartifactKeyData, err := os.ReadFile(artifactKeyFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read artifact key file: %w\", err)\n\t}\n","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/signer/artifactsign.go#L174-L210","documentation":"reposign.ValidateArtifact rejected the artifact; this is the security decision of verify-artifact and must never be bypassed. Concrete refusals in reposign/artifact.go:221-265: signature timestamp more than 5 minutes in the future (clock skew), signature older than 10 years, the signing key had expired at signature time, Ed25519 verification of the BLAKE2s hash/length/timestamp message failed (artifact bytes changed or wrong key), or no key with the signature's KeyID is in the supplied key list.","triggerScenarios":"Artifact rebuilt but not re-signed (hash mismatch); --artifact-public-key-file is a different key than the signer used (\"no signing Key found with ID ...\"); host clock more than 5 minutes fast; signing key expired between signing and verifying; artifact or .sig truncated during transfer.","commonSituations":"Release pipeline re-builds the binary after signing; verifier uses an old/new key rotation mismatch; VM clock drift in CI; partially downloaded artifact.","solutions":["Confirm the artifact is byte-identical to what was signed: compare sha256sum against the value at signing time","Check the key pair matches: the KeyID printed on successful signing must equal the ID embedded in --artifact-public-key-file","Sync the system clock (max allowed skew is 5 minutes) and re-verify","If the signing key expired, re-sign with a current artifact key and republish"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := reposign.ValidateArtifact([]reposign.PublicKey{publicKey}, artifactData, *signature); err != nil {\n    switch {\n    case strings.Contains(err.Error(), \"no signing Key found\"):\n        log.Fatalf(\"key file does not match signer KeyID %s\", signature.KeyID)\n    case strings.Contains(err.Error(), \"timestamp is in the future\"), strings.Contains(err.Error(), \"too old\"):\n        log.Fatalf(\"clock/timestamp problem: %v\", err)\n    default:\n        log.Fatalf(\"VERIFICATION FAILED, do not ship: %v\", err)\n    }\n}","preventionTips":["Treat any verification failure as fatal; never fall back to shipping unverified artifacts","Log the artifact sha256 and signature KeyID at signing time so mismatches are diagnosable","Keep verifier clocks NTP-synced (5-minute skew budget)","Rotate artifact keys before their ExpiresAt and republish the root-signed bundle"],"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"}