{"record":{"id":"db6ea9d90cd00317","repo":"getsops/sops","slug":"failed-to-verify-data-integrity-expected-mac-q","errorCode":null,"errorMessage":"Failed to verify data integrity. expected mac %q, got %q","messagePattern":"Failed to verify data integrity\\. expected mac %q, got %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"decrypt/decrypt.go","lineNumber":67,"sourceCode":"\tcipher := aes.NewCipher()\n\tmac, err := tree.Decrypt(key, cipher)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Compute the hash of the cleartext tree and compare it with\n\t// the one that was stored in the document. If they match,\n\t// integrity was preserved\n\toriginalMac, err := cipher.Decrypt(\n\t\ttree.Metadata.MessageAuthenticationCode,\n\t\tkey,\n\t\ttree.Metadata.LastModified.Format(time.RFC3339),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"Failed to decrypt original mac: %w\", err)\n\t}\n\tif originalMac != mac {\n\t\treturn nil, fmt.Errorf(\"Failed to verify data integrity. expected mac %q, got %q\", originalMac, mac)\n\t}\n\n\treturn store.EmitPlainFile(tree.Branches)\n}\n\n// Data is a helper that takes encrypted data and a format string,\n// decrypts the data and returns its cleartext in an []byte.\n// The format string can be `json`, `yaml`, `ini`, `dotenv` or `binary`.\n// If the format string is empty, binary format is assumed.\nfunc Data(data []byte, format string) (cleartext []byte, err error) {\n\tformatFmt := FormatFromString(format)\n\treturn DataWithFormat(data, formatFmt)\n}\n","sourceCodeStart":49,"sourceCodeEnd":81,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/decrypt/decrypt.go#L49-L81","documentation":"After decrypting the stored MAC, DataWithFormat compares it with a freshly computed MAC over the cleartext. A mismatch means the encrypted data does not match its metadata — the plaintext was tampered with, partially written, or the file was edited outside sops. sops refuses to return the data because integrity cannot be guaranteed.","triggerScenarios":"originalMac != mac: manual edits to the encrypted file's data branches, truncation by a partial upload/download, differing newline or encoding transformations between encryption and decryption, or decrypting a file whose metadata belongs to a different version.","commonSituations":"Pipeline stages that strip whitespace or convert line endings (CRLF/LF) before sops runs; git merge of an encrypted file without re-encrypting; checksum-mismatched S3 download; concatenating sops files or copy-pasting encrypted content through editors.","solutions":["Restore the original encrypted file from its source of truth (git, S3 versioning) and decrypt again","Never edit encrypted sops files by hand — edit plaintext via sops editor mode and re-encrypt","Re-encrypt the known-good plaintext with sops -e to regenerate consistent metadata if the original is lost","Rule out transport mangling: download with checksum verification, keep binary-safe transfers, normalize line endings consistently"],"exampleFix":"// before (transforming the encrypted bytes in-flight corrupts MAC)\nprocessed := strings.ReplaceAll(string(encBytes), \"\\r\\n\", \"\\n\")\nplain, err := decrypt.Data([]byte(processed), \"yaml\")\n// after\nplain, err := decrypt.Data(encBytes, \"yaml\") // pass bytes untouched","handlingStrategy":"try-catch","validationCode":"// detect likely mangling before decryption: mixed line endings or unexpected edits\nif bytes.Contains(encBytes, []byte(\"\\r\\n\")) && bytes.Contains(encBytes, []byte(\"\\n\")) {\n    return errors.New(\"encrypted input has mixed line endings; likely modified in transit\")\n}","typeGuard":null,"tryCatchPattern":"plain, err := decrypt.DataWithFormat(encBytes, formatFmt)\nif err != nil {\n    if strings.Contains(err.Error(), \"Failed to verify data integrity\") {\n        return fmt.Errorf(\"encrypted data does not match its metadata; restore the original file and never edit encrypted files directly: %w\", err)\n    }\n    return err\n}","preventionTips":["Treat sops-encrypted files as immutable — edit only via sops editor mode","Avoid any transformation (trims, CRLF conversion, pretty-printing) of encrypted bytes","Use git merge=ours / re-encrypt workflows to prevent merges of encrypted files","Verify download integrity (checksums, S3 versioning) before decrypting"],"tags":["decryption","mac","integrity","tampering","sops"],"backgroundTag":"mac-verification-failed","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}