{"record":{"id":"85252e2592f13222","repo":"Tencent/WeKnora","slug":"plaintext-too-short","errorCode":null,"errorMessage":"plaintext too short","messagePattern":"plaintext too short","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/im/wecom/webhook_adapter.go","lineNumber":484,"sourceCode":"\tiv := a.aesKey[:aes.BlockSize]\n\tmode := cipher.NewCBCDecrypter(block, iv)\n\tmode.CryptBlocks(ciphertext, ciphertext)\n\n\t// Remove and verify PKCS#7 padding\n\tpadLen := int(ciphertext[len(ciphertext)-1])\n\tif padLen > wecomPKCS7BlockSize || padLen == 0 || padLen > len(ciphertext) {\n\t\treturn nil, fmt.Errorf(\"invalid padding\")\n\t}\n\tfor i := 0; i < padLen; i++ {\n\t\tif ciphertext[len(ciphertext)-1-i] != byte(padLen) {\n\t\t\treturn nil, fmt.Errorf(\"invalid padding\")\n\t\t}\n\t}\n\tplaintext := ciphertext[:len(ciphertext)-padLen]\n\n\t// WeCom format: random(16) + msg_len(4) + msg + corp_id\n\tif len(plaintext) < 20 {\n\t\treturn nil, fmt.Errorf(\"plaintext too short\")\n\t}\n\n\tmsgLen := binary.BigEndian.Uint32(plaintext[16:20])\n\tif uint32(len(plaintext)) < 20+msgLen {\n\t\treturn nil, fmt.Errorf(\"message length mismatch\")\n\t}\n\n\tmsgBytes := plaintext[20 : 20+msgLen]\n\n\t// Verify corp_id from plaintext tail\n\tcorpIDBytes := plaintext[20+msgLen:]\n\tif string(corpIDBytes) != a.corpID {\n\t\treturn nil, fmt.Errorf(\"corp_id mismatch: expected %s, got %s\", a.corpID, string(corpIDBytes))\n\t}\n\n\treturn msgBytes, nil\n}\n","sourceCodeStart":466,"sourceCodeEnd":502,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/im/wecom/webhook_adapter.go#L466-L502","documentation":"WeCom plaintext has the layout random(16 bytes) + msg_len(4 bytes, big-endian) + msg + corp_id, so at least 20 bytes are required before the message-length field can even be read. decrypt() returns this error when the unpadded plaintext is shorter than 20 bytes. It almost always accompanies a key mismatch that yielded garbage padding, or a genuinely truncated payload.","triggerScenarios":"PKCS#7 padding with padLen close to 16 stripping nearly all bytes from a short/garbage plaintext; decrypting non-WeCom data that happens to pass padding checks; severely truncated callback payloads.","commonSituations":"Wrong EncodingAESKey producing valid-looking-but-garbage padding; a test posting tiny payloads; intermediary systems compressing or transforming the encrypted body.","solutions":["Fix the underlying key mismatch first — a correct key on real WeCom data always yields >= 20 bytes of plaintext","Check for truncation of the Encrypt field upstream (proxies, logs, form parsing) and pass the raw body bytes","Validate the decrypted length sanity in tests by encrypting a sample via the official WeCom crypto sample","Confirm the base64 decode uses StdEncoding, not URL-safe variants"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func hasWeComPlaintextLayout(plaintext []byte) bool { return len(plaintext) >= 20 }","tryCatchPattern":"msg, err := adapter.ParseCallback(sig, ts, nonce, enc)\nif err != nil && strings.Contains(err.Error(), \"plaintext too short\") {\n    // almost always a key mismatch; treat as bad request\n    http.Error(w, \"bad payload\", http.StatusBadRequest)\n    return\n}","preventionTips":["Fix 'invalid padding' root causes (key mismatch) — this error rarely occurs alone","Never feed hand-crafted short payloads to decrypt outside tests"],"tags":["aes","decryption","payload-format","wecom"],"backgroundTag":"plaintext-too-short","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}