{"record":{"id":"7e512df6b9966f73","repo":"vxcontrol/pentagi","slug":"invalid-blob-hash-q","errorCode":null,"errorMessage":"invalid blob hash %q","messagePattern":"invalid blob hash %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/resources/resources.go","lineNumber":96,"sourceCode":"}\n\n// IsValidBlobHash reports whether hash is a hex-encoded MD5 digest.\nfunc IsValidBlobHash(hash string) bool {\n\tif len(hash) != md5.Size*2 {\n\t\treturn false\n\t}\n\tfor _, r := range hash {\n\t\tif (r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F') {\n\t\t\tcontinue\n\t\t}\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc validateBlobHash(hash string) error {\n\tif !IsValidBlobHash(hash) {\n\t\treturn fmt.Errorf(\"invalid blob hash %q\", hash)\n\t}\n\treturn nil\n}\n\n// BlobExists returns true if the .blob file for hash already exists on disk.\nfunc BlobExists(dataDir, hash string) (bool, error) {\n\tif err := validateBlobHash(hash); err != nil {\n\t\treturn false, err\n\t}\n\t_, err := os.Lstat(BlobPath(dataDir, hash))\n\tif err == nil {\n\t\treturn true, nil\n\t}\n\tif os.IsNotExist(err) {\n\t\treturn false, nil\n\t}\n\treturn false, err\n}","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/resources/resources.go#L78-L114","documentation":"validateBlobHash (resources.go:96) rejects any hash that is not a valid hex-encoded MD5 digest, as checked by IsValidBlobHash. BlobExists, DeleteBlob, and CommitBlob all call it first, so blob APIs never touch disk with a malformed hash. The error includes the offending value with %q so empty strings, non-hex characters, and wrong lengths are immediately visible.","triggerScenarios":"Passing an empty string, a SHA-256/sha1 hash instead of a 32-char MD5 hex, an uppercase or '0x'-prefixed hash if IsValidBlobHash rejects it, or a hash containing path separators (which would otherwise enable path traversal) to BlobExists, DeleteBlob, or CommitBlob.","commonSituations":"Migrating from another storage scheme that used different hash algorithms; trusting user- or API-supplied hash parameters without validating; stale DB records containing truncated or legacy hashes; copy/paste errors including whitespace or quotes.","solutions":["Print the hash value from the error and verify it is exactly 32 lowercase hex characters (regex ^[0-9a-f]{32}$)","Recompute the correct MD5 with ComputeFileMD5 from the source content instead of reusing the stored/external value","Trim whitespace and lowercase the input before calling blob APIs if your source may vary in case","If you migrate hash algorithms, re-hash and update stored references rather than passing new-format hashes to these APIs"],"exampleFix":"// before\nexists, err := resources.BlobExists(dataDir, userHash) // may be arbitrary input\n// after\nvar md5Re = regexp.MustCompile(`^[0-9a-f]{32}$`)\nif !md5Re.MatchString(strings.TrimSpace(userHash)) { return fmt.Errorf(\"bad hash %q\", userHash) }\nexists, err := resources.BlobExists(dataDir, strings.TrimSpace(userHash))","handlingStrategy":"validation","validationCode":"var md5HexRe = regexp.MustCompile(`^[0-9a-f]{32}$`)\nfunc validBlobHash(h string) bool { return md5HexRe.MatchString(h) }","typeGuard":"func isBlobHash(s string) bool {\n    if len(s) != 32 { return false }\n    for _, c := range s {\n        if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) { return false }\n    }\n    return true\n}","tryCatchPattern":"if !isBlobHash(hash) { return fmt.Errorf(\"skip invalid hash %q\", hash) }\nif err := resources.DeleteBlob(dataDir, hash); err != nil {\n    if strings.Contains(err.Error(), \"invalid blob hash\") { return errInvalidInput }\n    return err\n}","preventionTips":["Run resources.IsValidBlobHash(hash) before any blob API call with untrusted input","Normalize hashes to lowercase and trim whitespace at system boundaries","Store only hashes produced by ComputeFileMD5; never accept hashes from external systems unchanged","Add a unit test asserting blob APIs reject empty and malformed hashes"],"tags":["validation","hash","input"],"backgroundTag":"invalid-hash-format","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}