{"record":{"id":"779fec8e32d67555","repo":"Tencent/WeKnora","slug":"message-length-mismatch","errorCode":null,"errorMessage":"message length mismatch","messagePattern":"message length mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/im/wecom/webhook_adapter.go","lineNumber":489,"sourceCode":"\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\n// callbackRequestBody is the XML structure of a WeCom callback request body.\ntype callbackRequestBody struct {\n\tXMLName    xml.Name `xml:\"xml\"`\n\tToUserName string   `xml:\"ToUserName\"`\n\tEncrypt    string   `xml:\"Encrypt\"`","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/im/wecom/webhook_adapter.go#L471-L507","documentation":"decrypt() reads msgLen from plaintext[16:20] (big-endian uint32) and requires len(plaintext) >= 20+msgLen, i.e. the declared message must actually fit in the buffer. A mismatch means the length header doesn't match the remaining bytes — the signature of decrypting with the wrong key or of corrupted/truncated data. It prevents slicing out-of-bounds or trusting attacker-controlled lengths.","triggerScenarios":"Garbage msgLen from a wrong-key decryption; ciphertext truncated mid-message; crafted callback bodies where the embedded length exceeds the actual plaintext (possibly malicious).","commonSituations":"Wrong EncodingAESKey (most common); truncation by an HTTP intermediary; malicious forged callbacks probing the parser — this check is a security boundary.","solutions":["Verify the EncodingAESKey matches the sending WeCom app — this error after 'invalid padding' style symptoms is nearly always a key mismatch","Log msgLen vs len(plaintext) to distinguish key corruption (random msgLen) from truncation (msgLen slightly larger than buffer)","Ensure no proxy rewrites the request body between WeCom and your endpoint","Treat repeated mismatches as potential forged traffic and enable signature verification of msg_signature before decrypt"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"message length mismatch\") {\n    logger.Warnf(\"WeCom callback length mismatch (forged or corrupted?) sig=%s\", msgSignature)\n    http.Error(w, \"bad payload\", http.StatusBadRequest)\n    return\n}","preventionTips":["Always verify msg_signature (HMAC-SHA1 of token/timestamp/nonce/encrypt) before decrypt so forged bodies never reach this check","Keep proxies from rewriting the callback body","Monitor mismatches as a security signal"],"tags":["aes","decryption","payload-format","wecom"],"backgroundTag":"message-length-mismatch","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}