{"record":{"id":"e83cbc9decbcf8eb","repo":"chenhg5/cc-connect","slug":"wecom-ws-empty-padded-data","errorCode":null,"errorMessage":"wecom-ws: empty padded data","messagePattern":"wecom-ws: empty padded data","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"platform/wecom/websocket_media.go","lineNumber":295,"sourceCode":"\t}\n\tkey32 := key[:32]\n\tiv := key32[:16]\n\n\tblock, err := aes.NewCipher(key32)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(ciphertext)%aes.BlockSize != 0 {\n\t\treturn nil, fmt.Errorf(\"wecom-ws: ciphertext not multiple of block size\")\n\t}\n\tplain := make([]byte, len(ciphertext))\n\tcipher.NewCBCDecrypter(block, iv).CryptBlocks(plain, ciphertext)\n\treturn pkcs7UnpadWeCom(plain)\n}\n\nfunc pkcs7UnpadWeCom(data []byte) ([]byte, error) {\n\tif len(data) == 0 {\n\t\treturn nil, fmt.Errorf(\"wecom-ws: empty padded data\")\n\t}\n\tpadLen := int(data[len(data)-1])\n\tif padLen < 1 || padLen > 32 || padLen > len(data) {\n\t\treturn nil, fmt.Errorf(\"wecom-ws: invalid pkcs7 pad length %d\", padLen)\n\t}\n\tfor i := len(data) - padLen; i < len(data); i++ {\n\t\tif int(data[i]) != padLen {\n\t\t\treturn nil, fmt.Errorf(\"wecom-ws: invalid pkcs7 padding\")\n\t\t}\n\t}\n\treturn data[:len(data)-padLen], nil\n}\n\nfunc parseContentDispositionFilename(h string) string {\n\th = strings.TrimSpace(h)\n\tif h == \"\" {\n\t\treturn \"\"\n\t}","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/wecom/websocket_media.go#L277-L313","documentation":"pkcs7UnpadWeCom refuses to unpad a zero-length plaintext buffer. In this code path it is effectively unreachable via wecomDecryptFile (ciphertext is validated as a non-empty multiple of 16 first), but it is exported as a guard for direct callers. It protects the last-byte pad-length read from an index panic.","triggerScenarios":"Calling pkcs7UnpadWeCom directly with an empty (or nil) slice — e.g. decrypting produced a zero-length buffer or a caller passed a manually decrypted empty block stream.","commonSituations":"Custom decryption pipelines reusing the helper; tests exercising edge cases; refactoring that moved the empty check out of wecomDecryptFile.","solutions":["Check len(data) == 0 before calling pkcs7UnpadWeCom, or rely on wecomDecryptFile which pre-validates ciphertext.","If data is empty after decryption, treat the media as corrupt and re-download rather than unpadding."],"exampleFix":"// before\nplain := make([]byte, 0)\nout, err := pkcs7UnpadWeCom(plain)\n// after\nif len(plain) == 0 {\n    return nil, fmt.Errorf(\"nothing decrypted\")\n}\nout, err := pkcs7UnpadWeCom(plain)","handlingStrategy":"type-guard","validationCode":"if plain == nil || len(plain) == 0 {\n    return nil, fmt.Errorf(\"nothing to unpad\")\n}","typeGuard":"func nonEmpty(b []byte) bool { return len(b) > 0 }","tryCatchPattern":null,"preventionTips":["Prefer calling wecomDecryptFile (which pre-validates) over pkcs7UnpadWeCom directly.","Handle zero-length decrypt results explicitly in custom pipelines."],"tags":["wecom","crypto","pkcs7","edge-case"],"backgroundTag":"empty-required-field","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}