{"record":{"id":"6d572a1d96fbb558","repo":"tinyhumansai/openhuman","slug":"encrypted-payload-too-short","errorCode":null,"errorMessage":"encrypted payload too short","messagePattern":"encrypted payload too short","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/api/rest.rs","lineNumber":1140,"sourceCode":"        self.authed_json(\n            bearer_jwt,\n            Method::DELETE,\n            &format!(\"auth/integrations/{id}\"),\n            None,\n        )\n        .await?;\n        Ok(())\n    }\n}\n\n/// AES-256-GCM decrypt compatible with backend `encryptMessageFromString` (IV 16 + tag 16 + ciphertext, base64).\npub fn decrypt_handoff_blob(b64_ciphertext: &str, key_str: &str) -> Result<String> {\n    let key = key_bytes_from_string(key_str)?;\n    let combined = base64::engine::general_purpose::STANDARD\n        .decode(b64_ciphertext.trim())\n        .context(\"base64-decode encrypted payload\")?;\n    if combined.len() < 32 {\n        anyhow::bail!(\"encrypted payload too short\");\n    }\n    let iv = &combined[0..16];\n    let tag = &combined[16..32];\n    let ciphertext = &combined[32..];\n\n    // aes-gcm expects ciphertext || tag\n    let mut ct_with_tag = Vec::with_capacity(ciphertext.len() + tag.len());\n    ct_with_tag.extend_from_slice(ciphertext);\n    ct_with_tag.extend_from_slice(tag);\n\n    use aes_gcm::aead::generic_array::typenum::U16;\n    use aes_gcm::aead::{Aead, KeyInit};\n    use aes_gcm::aes::Aes256;\n    use aes_gcm::AesGcm;\n    type Aes256Gcm16 = AesGcm<Aes256, U16>;\n\n    let cipher =\n        Aes256Gcm16::new_from_slice(&key).map_err(|e| anyhow::anyhow!(\"invalid AES key: {e}\"))?;","sourceCodeStart":1122,"sourceCodeEnd":1158,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/api/rest.rs#L1122-L1158","documentation":"decrypt_handoff_blob base64-decodes the payload and requires at least 32 bytes (16-byte IV + 16-byte GCM tag) before any ciphertext can exist; anything shorter bails with 'encrypted payload too short'. The blob is produced by the backend's encryptMessageFromString (IV || tag || ciphertext, standard base64), so a short payload means truncation or wrong encoding - it is never a key problem (key length is checked separately).","triggerScenarios":"The handoff blob was truncated in transit: cut off in a URL query param, clipboard copy, or log line; the payload was re-encoded (hex, base64url, double-encoded) instead of standard base64; an empty or placeholder string was passed.","commonSituations":"Deep-link or query-param handoff where the blob got trimmed by length limits; pasting blobs through tools that strip characters; a backend change to the wire format.","solutions":["Verify the payload is complete, standard base64 and decodes to at least 32 bytes.","Re-issue the handoff from the source system rather than hand-repairing the string.","Confirm the backend still uses the IV16 + tag16 + ciphertext layout of encryptMessageFromString.","Do not strip characters beyond the leading and trailing whitespace the function already trims."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn handoff_blob_decodes_long_enough(b64: &str) -> bool {\n    use base64::Engine;\n    base64::engine::general_purpose::STANDARD\n        .decode(b64.trim())\n        .map(|raw| raw.len() >= 32)\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate blob length before decryption so users get a 'truncated link' message instead of a crypto error.","Pass handoff blobs through channels that do not truncate (POST bodies or full URLs), not clipped log lines.","Pin the wire format (IV16 + tag16 + ciphertext, standard base64) in tests against the backend's encryptMessageFromString."],"tags":["crypto","aes-gcm","base64","handoff","payload-validation"],"backgroundTag":"invalid-encrypted-payload","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}