{"record":{"id":"d8a24ea290423f60","repo":"chenhg5/cc-connect","slug":"wecom-ws-invalid-pkcs7-padding","errorCode":null,"errorMessage":"wecom-ws: invalid pkcs7 padding","messagePattern":"wecom-ws: invalid pkcs7 padding","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/wecom/websocket_media.go","lineNumber":303,"sourceCode":"\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}\n\tlower := strings.ToLower(h)\n\t// RFC 5987: filename*=UTF-8''percent-encoded\n\tif idx := strings.Index(lower, \"filename*=\"); idx >= 0 {\n\t\tval := strings.TrimSpace(h[idx+len(\"filename*=\"):])\n\t\tval = strings.TrimSuffix(strings.TrimSpace(val), \";\")\n\t\tif after, ok := strings.CutPrefix(val, \"UTF-8''\"); ok {\n\t\t\tif dec, err := url.QueryUnescape(after); err == nil {\n\t\t\t\treturn filepath.Base(dec)","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/wecom/websocket_media.go#L285-L321","documentation":"After the pad length passes range validation, pkcs7UnpadWeCom verifies that all padLen trailing bytes equal padLen (proper PKCS7 padding). If any byte differs, the padding is malformed — again almost always a symptom of decrypting with an incorrect AES key or corrupted ciphertext, producing random-looking trailing bytes.","triggerScenarios":"wecomDecryptFile with wrong key or bit-flipped ciphertext; last byte happened to be a plausible 1–32 value but the remaining pad bytes don't match.","commonSituations":"Mixed-up keys between bots/environments; ciphertext truncated and re-padded by an intermediary; flaky storage corrupting the downloaded bytes.","solutions":["Confirm the EncodingAESKey belongs to the same bot/app that issued the media URL.","Compare the SHA-256 of the downloaded ciphertext against the source (or re-download) to rule out transfer corruption.","Sanity-check the rest of the plaintext: if it's entirely binary noise, the key is wrong; if only padding fails, suspect corruption."],"exampleFix":"// before\nsum := sha256.Sum256(raw)\n// skip verification\nplain, err := wecomDecryptFile(raw, key)\n// after\nif got := sha256.Sum256(raw); !bytes.Equal(got[:], expectedSum) {\n    return nil, fmt.Errorf(\"ciphertext corrupted in transit\")\n}\nplain, err := wecomDecryptFile(raw, key)","handlingStrategy":"retry","validationCode":"if got := sha256.Sum256(raw); expectedSum != nil && !bytes.Equal(got[:], expectedSum) {\n    return fmt.Errorf(\"ciphertext corrupted\")\n}","typeGuard":null,"tryCatchPattern":"plain, err := wecomDecryptFile(raw, key)\nif err != nil && strings.Contains(err.Error(), \"invalid pkcs7 padding\") {\n    // re-download once with a fresh URL, then surface a wrong-key/corruption error\n}","preventionTips":["Verify transfer integrity (Content-Length, checksum) before decrypting.","Map padding failures to wrong-key diagnostics in logs.","One retry with a fresh media URL before giving up."],"tags":["wecom","crypto","pkcs7","integrity"],"backgroundTag":"checksum-mismatch","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"}