Feb 14, 2026·6 min read·13 visits
rPGP failed to consistently verify the cryptographic integrity (MDC) of encrypted messages. This allowed Man-in-the-Middle attackers to modify ciphertext without detection, leading to potential data exfiltration via 'In-Band Signaling' attacks in downstream applications like Delta Chat.
A critical logic flaw in the rPGP OpenPGP implementation allowed attackers to bypass message integrity checks. By failing to strictly verify the Modification Detection Code (MDC) in encrypted packets, the library exposed applications like Delta Chat to ciphertext manipulation and 'In-Band Signaling' attacks. This vulnerability highlights the dangers of legacy OpenPGP complexity even in modern, memory-safe languages like Rust.
OpenPGP is the cockroach of the cryptographic world. It predates modern authenticated encryption (AEAD) by decades, surviving through a patchwork of backward compatibility and 'good enough' fixes. One of those fixes was the Modification Detection Code (MDC)—a desperate attempt to stop attackers from tampering with encrypted messages. Before MDC, OpenPGP used malleable encryption (like CAST5 or AES in CFB mode), meaning if I flipped a bit in your ciphertext, I could predictably flip a bit in your plaintext. Scary stuff.
Enter rPGP, a pure Rust implementation of OpenPGP. Rust is the golden child of security, promising memory safety and concurrency without data races. But here's the kicker: Rust protects you from buffer overflows, not from logic errors. GHSA-C7PH-F7JM-XV4W is exactly that—a logic bug where the library decided that checking the integrity of a message was strictly optional.
Researchers from ETH Zurich discovered that rPGP would sometimes happily decrypt and return a message even if the MDC was missing, malformed, or invalid. This turns a modern secure messenger (like Delta Chat, which uses rPGP) into a 1990s-era pager that blindly trusts whatever garbage comes over the wire.
To understand why this breaks everything, you have to understand the Symmetrically Encrypted Integrity Protected (SEIP) packet (Tag 18). In the OpenPGP standard (RFC 4880), SEIP wraps the actual data and appends a SHA-1 hash (the MDC) at the end. The decryption process is supposed to look like this:
rPGP failed at step 4. In specific edge cases, the parser would encounter an issue or simply reach the end of the stream and return the decrypted data before confirming the MDC was valid. This effectively downgraded the encryption from 'Authenticated' to 'Malleable'.
When encryption is malleable (specifically in CFB mode, which OpenPGP uses), an attacker can manipulate the ciphertext to introduce errors in the plaintext. While they can't decrypt the message themselves, they can corrupt it. Without an integrity check, the application receives this corrupted data as if it were legitimate. This is the foundation of the 'In-Band Signaling' attack described by the researchers.
The vulnerability lies in the separation between decrypting the stream and verifying the stream. In a robust implementation, these two actions must be atomic—you do not yield data until you verify it. The rPGP implementation, prior to version 0.11.0, allowed a disconnect.
Below is a conceptual simplification of the flaw. The iterator processing the packet stream would yield the content of the SEIP packet effectively 'lazily'. If the stream ended abruptly or the MDC packet was malformed, the error might be logged or raised, but the consumer of the library might have already processed the partial/corrupted plaintext.
// CONCEPTUAL VULNERABLE LOGIC
// The library might yield decrypted chunks before final validation
fn decrypt_packet(packet: EncryptedPacket) -> Result<Vec<u8>, Error> {
let mut plaintext = Vec::new();
// ... decryption loop ...
// The flaw: If the MDC is missing or the loop breaks early,
// the function might return what it has instead of a hard error.
if mdc_check_failed {
// In some paths, this was ignored or treated as a soft warning
// allowing the caller to access 'plaintext'.
}
Ok(plaintext)
}The fix in v0.11.0 enforces a strict check. The library now ensures that the MDC packet is present and valid before considering the decryption successful. It moves the implementation closer to a 'Release-Unverified' prohibition, ensuring that if the integrity check fails, the data is treated as radioactive waste.
How do you weaponize a missing checksum? You use the application against itself. The ETH Zurich researchers demonstrated an In-Band Signaling (IBS) attack against Delta Chat. Since rPGP didn't stop modified ciphertexts, an attacker (Alice) could intercept a message to Bob and inject a 'signal'.
Here is the attack flow:
N scrambles block N (garbage) but flips the specific bit in block N+1.This bypasses the fundamental promise of cryptography: "If you touch the message, I will know, and I will reject it."
The immediate fix is simple: Upgrade rPGP to version 0.11.0. This version introduces strict MDC verification logic that refuses to yield plaintext if the integrity check fails.
However, the long-term fix is to stop using 1990s cryptography. The OpenPGP community has finally released RFC 9580 (Crypto Refresh), which officially deprecates the older SEIP mechanism in favor of true AEAD (Authenticated Encryption with Associated Data) modes like OCB, EAX, or GCM. AEAD designs integrate authentication into the encryption process itself, rather than tacking a hash onto the end like a post-it note.
> [!TIP]
> For Developers: If you are using rPGP or any OpenPGP library, audit your usage. Do not assume the library handles errors safely by default. Explicitly check for verification success types in your code.
For users of Delta Chat, verify you are running version 1.44 or later. If you are building on top of pgp crate, check your Cargo.lock immediately.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
rPGP rPGP | <= 0.10.2 | 0.11.0 |
Delta Chat Core Merlin | < 1.132.0 | 1.132.0 |
| Attribute | Detail |
|---|---|
| CWE | CWE-347 (Improper Verification of Cryptographic Signature) |
| Attack Vector | Network (Man-in-the-Middle) |
| CVSS v3.1 | 6.5 (Medium) |
| Impact | Integrity Loss / Data Exfiltration |
| Affected Protocol | OpenPGP (SEIP / Tag 18) |
| Fix Version | 0.11.0 |
The software does not verify, or incorrectly verifies, the cryptographic signature or integrity code (MDC) of data, allowing modification.