{"record":{"id":"4dbb913a04789964","repo":"chenhg5/cc-connect","slug":"invalid-padded-length-d","errorCode":null,"errorMessage":"invalid padded length %d","messagePattern":"invalid padded length (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/weixin/cdn.go","lineNumber":42,"sourceCode":"func aesECBPaddedSize(plaintextLen int) int {\n\tif plaintextLen < 0 {\n\t\treturn 0\n\t}\n\treturn ((plaintextLen + aes.BlockSize) / aes.BlockSize) * aes.BlockSize\n}\n\nfunc pkcs7Pad(b []byte, blockSize int) []byte {\n\tif blockSize <= 0 || blockSize > 255 {\n\t\tpanic(\"invalid block size\")\n\t}\n\tn := blockSize - (len(b) % blockSize)\n\tpad := bytes.Repeat([]byte{byte(n)}, n)\n\treturn append(b, pad...)\n}\n\nfunc pkcs7Unpad(b []byte, blockSize int) ([]byte, error) {\n\tif len(b) == 0 || len(b)%blockSize != 0 {\n\t\treturn nil, fmt.Errorf(\"invalid padded length %d\", len(b))\n\t}\n\tn := int(b[len(b)-1])\n\tif n == 0 || n > blockSize || n > len(b) {\n\t\treturn nil, fmt.Errorf(\"invalid pkcs7 padding\")\n\t}\n\tfor i := len(b) - n; i < len(b); i++ {\n\t\tif b[i] != byte(n) {\n\t\t\treturn nil, fmt.Errorf(\"invalid pkcs7 padding\")\n\t\t}\n\t}\n\treturn b[:len(b)-n], nil\n}\n\nfunc encryptAESECB(plaintext, key []byte) ([]byte, error) {\n\tif len(key) != 16 {\n\t\treturn nil, fmt.Errorf(\"aes key must be 16 bytes, got %d\", len(key))\n\t}\n\tblock, err := aes.NewCipher(key)","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/weixin/cdn.go#L24-L60","documentation":"pkcs7Unpad in the Weixin CDN helper validates that the buffer being unpadded is non-empty and an exact multiple of the AES block size (16). If the decrypted ciphertext has a padded length that fails this check, it returns 'invalid padded length %d' with the actual byte count. This means the input to unpad was not a valid block-aligned PKCS7 buffer, so decryption produced garbage or was truncated.","triggerScenarios":"decryptAESECB called with a ciphertext whose length is not a multiple of 16 (the length check precedes it, so this fires mainly for len==0 or when unpad is called directly on non-aligned data); truncated CDN download where the tail bytes are missing; calling pkcs7Unpad on an empty slice.","commonSituations":"Interrupted/partial WeChat CDN file download before AES decryption; version change in CDN payload framing; misuse of the helper on raw (unencrypted) bytes.","solutions":["Verify the downloaded ciphertext is complete (compare against the expected file size) before decrypting","Re-download the CDN media; do not call pkcs7Unpad directly on unencrypted data","Check that decryptAESECB received the full, block-aligned buffer"],"exampleFix":"// before\ndata, _ := io.ReadAll(resp.Body)\nplain, err := decryptAESECB(data, key)\n// after\ndata, _ := io.ReadAll(resp.Body)\nif len(data) == 0 || len(data)%16 != 0 {\n    return nil, fmt.Errorf(\"cdn: incomplete download, got %d bytes\", len(data))\n}\nplain, err := decryptAESECB(data, key)","handlingStrategy":"validation","validationCode":"if len(cipher) == 0 || len(cipher)%aes.BlockSize != 0 {\n    return fmt.Errorf(\"cdn: bad ciphertext length %d\", len(cipher))\n}\nplain, err := decryptAESECB(cipher, key)","typeGuard":null,"tryCatchPattern":"plain, err := decryptAESECB(data, key)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid padded length\") {\n        return redownloadAndDecrypt(media) // truncated payload\n    }\n    return err\n}","preventionTips":["Always validate downloaded size against Content-Length before decrypting","Never call pkcs7Unpad directly; go through decryptAESECB which pre-validates","Retry CDN downloads once on decryption failure","Check HTTP status codes on CDN responses"],"tags":["weixin","crypto","pkcs7","aes"],"backgroundTag":"invalid-argument-value","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}