{"record":{"id":"66f700b2e4392d1d","repo":"hashicorp/terraform","slug":"errnotsignedbyhashicorp","errorCode":"ErrNotSignedByHashiCorp","errorMessage":"failed to authenticate that the archive was signed by HashiCorp","messagePattern":"failed to authenticate that the archive was signed by HashiCorp","errorType":"exception","errorClass":"ErrNotSignedByHashiCorp","httpStatus":null,"severity":"critical","filePath":"internal/releaseauth/signature.go","lineNumber":32,"sourceCode":"\topenpgpErrors \"github.com/ProtonMail/go-crypto/openpgp/errors\"\n)\n\n// SignatureAuthentication is an archive Authenticator that validates that SHA256SUMS data\n// was signed by the given signing key.\ntype SignatureAuthentication struct {\n\tAuthenticator\n\n\t// This can be overridden by tests to check arbitrary keys, rather than the HashiCorp public key\n\tPublicKey string\n\tsignature []byte\n\tsigned    []byte\n}\n\nvar _ Authenticator = SignatureAuthentication{}\n\n// ErrNotSignedByHashiCorp is the error returned when there is a mismatch between the SHA256SUMS\n// signature data and the data itself.\nvar ErrNotSignedByHashiCorp = errors.New(\"failed to authenticate that the archive was signed by HashiCorp\")\n\n// NewSignatureAuthentication creates a new Authenticator given some signature data\n// (the SHA256SUMS.sig file), the signed data (the SHA256SUMS file), and a public key\nfunc NewSignatureAuthentication(signature []byte, signed []byte) *SignatureAuthentication {\n\treturn &SignatureAuthentication{\n\t\tsignature: signature,\n\t\tsigned:    signed,\n\t\tPublicKey: HashiCorpPublicKey,\n\t}\n}\n\nfunc (a SignatureAuthentication) Authenticate() error {\n\t// Verify the signature using the HashiCorp public key. If this succeeds,\n\t// this is an official provider.\n\thashicorpKeyring, err := openpgp.ReadArmoredKeyRing(strings.NewReader(a.PublicKey))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating HashiCorp keyring: %s\", err)\n\t}","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/releaseauth/signature.go#L14-L50","documentation":"ErrNotSignedByHashiCorp is a sentinel from SignatureAuthentication.Authenticate: it verifies the detached OpenPGP signature of the SHA256SUMS file against the bundled HashiCorp public key (HashiCorpPublicKey, key ID 72D7468F). Any GPG verification failure other than an expired key (which is tolerated and logged) is collapsed into this error, meaning the signature could not be attributed to HashiCorp.","triggerScenarios":"Returned at internal/releaseauth/signature.go:61 when openpgp.CheckDetachedSignature returns a non-nil err that is not openpgpErrors.ErrKeyExpired. The Authenticator is built by NewSignatureAuthentication(signature, signed) using the downloaded SHA256SUMS.sig and SHA256SUMS.","commonSituations":"A corrupted or truncated SHA256SUMS or .sig download. A signature produced by a non-HashiCorp key (unofficial/forked provider repackaged as official). A mismatch between sig and sums (e.g. sums from a different release). An attacker-in-the-middle modifying either file. A provider whose sums were re-signed after HashiCorp rotated keys (note: expired key is allowed, but a fully replaced key is not).","solutions":["Re-download both SHA256SUMS and SHA256SUMS.sig fresh and retry; transient corruption is the most common cause.","Confirm you are installing the official provider build from the HashiCorp/registry release, not a repackaged fork.","Verify the bundled HashiCorp public key (72D7468F) matches the current well-known key at hashicorp.com/.well-known/pgp-key.txt; if HashiCorp rotated the signing key, upgrade Terraform to a version embedding the new key.","Inspect TF_LOG=DEBUG output for the specific GPG error (it is logged before this sentinel is returned).","If you legitimately mirror/re-sign internally, use a filesystem mirror with your own trust model rather than the registry path."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// No caller pre-check; the Authenticator does the verification.\n// Mitigate by re-downloading both .sig and sums from the canonical source first.","typeGuard":"func isNotSignedByHashiCorp(err error) bool {\n    return errors.Is(err, releaseauth.ErrNotSignedByHashiCorp)\n}","tryCatchPattern":"if err := sigAuth.Authenticate(); err != nil {\n    if errors.Is(err, releaseauth.ErrNotSignedByHashiCorp) {\n        // refuse to proceed; this is a potential supply-chain problem\n        return errors.New(\"refusing to install: archive not signed by HashiCorp\")\n    }\n    return err\n}","preventionTips":["Only install providers from the official HashiCorp registry/releases.","Keep Terraform current so the embedded HashiCorp public key (72D7468F) matches the active signing key.","Treat signature failure as fatal — never bypass it."],"tags":["release-auth","gpg","signature","integrity","supply-chain"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}