What compression-encryption interaction invariants must agents verify before transmitting?

**Date of Record:** 2026 October 26 **Scope:** Applies when an agentic session compresses and encrypts a payload before transmission (or receives such a payload), and the compression-encryption ordering, algorithm choice, and padding can interact to leak information or corrupt data. Does not apply to uncompressed or unencrypted transmissions, or to strictly authenticated encryption with integrated compression (e.g., AEAD with built-in compression).

Core Distinction

The separation between **independent compression** (compression is applied, then encryption is applied, as separate steps) and **safe compression-encryption composition** (the composition is designed so the compression does not leak information via the ciphertext length or timing, and the encryption does not corrupt the compressed payload). The naive order (compress-then-encrypt) is vulnerable to **CRIME/BREACH-style attacks** where an attacker uses ciphertext length as an oracle to recover plaintext.

What Was Observed

In secure agent communication architectures, failing to verify compression-encryption composition produces three primary failure modes:

  1. **Length Oracle Attack:** An attacker observes ciphertext length. If the plaintext contains their target string, it compresses better, resulting in a shorter ciphertext. By repeating with crafted inputs, the attacker recovers the secret.
  2. **Compression Bombs:** A maliciously crafted compressed payload expands to gigabytes when decompressed, exhausting memory. If the decompression happens before authentication verification, the agent is vulnerable.
  3. **Bleichenbacher-Style Padding Oracles:** The interaction between compression padding and encryption padding can leak information via error messages or timing, allowing adaptive chosen-ciphertext attacks.

Recorded Elements

  1. **`compression_algorithm_id`:** The exact compression algorithm (gzip, brotli, zstd, lz4) with the exact version, since compression algorithms have known length-leak profiles.
  2. **`encryption_algorithm_id`:** The exact encryption algorithm (AES-GCM, ChaCha20-Poly1305, etc.) with authentication guarantees and padding behavior.
  3. **`composition_order`:** The explicit order in which compression and encryption were applied, and whether the authentication tag covers both the ciphertext and the compression metadata.
  4. **`length_leak_mitigation`:** The exact padding or length-hiding technique applied to prevent length oracles (e.g., fixed-size chunks, random-length padding, or constant-length ciphertext).

Condition of Validity

* **Applies when:** The agent compresses and encrypts untrusted or sensitive payloads, and the adversary can observe ciphertext length or timing. * **Does not apply when:** The transport layer provides length hiding (e.g., constant-rate links), or the payload is strictly public and length leakage is inconsequential.

Decision Boundary

  1. **Does the transmission use independent compression and encryption steps?** If no (integrated AEAD or no compression), standard security applies. If yes, proceed.
  2. **Is the `length_leak_mitigation` present and appropriate for the threat model?** If no, the transmission is vulnerable to CRIME-style attacks. The instance must apply mitigation or disable compression.
  3. **Is the authentication tag verified before decompression?** If no, the agent is vulnerable to compression bombs. The instance must reorder to authenticate-then-decompress.
  4. **Conversely, when can an agent transmit compress-then-encrypt without mitigation?** Only when the attacker cannot observe ciphertext length (e.g., constant-rate transport) and the agent has bounded memory to prevent decompression bombs.

Operational Effect

  1. **Length Oracle Immunity:** Forces agents to hide ciphertext length, preventing CRIME-style plaintext recovery attacks.
  2. **Decompression Bomb Prevention:** Requires authentication before decompression, preventing denial-of-service via adversarial compressed payloads.
  3. **Padding Oracle Prevention:** Ensures the interaction between compression and encryption padding is safe, preventing Bleichenbacher-style attacks.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json

class CompositionVerdict(Enum):
    SAFE_COMPOSITION = auto()
    LENGTH_ORACLE_RISK = auto()
    DECOMPRESSION_BOMB_RISK = auto()
    PADDING_ORACLE_RISK = auto()

@dataclass(frozen=True)
class CompressionEncryptionConfig:
    compression_algorithm_id: str
    encryption_algorithm_id: str
    composition_order: str  # "COMPRESS_THEN_ENCRYPT", "ENCRYPT_THEN_COMPRESS", "INTEGRATED"
    length_leak_mitigation: str | None
    authenticate_before_decompress: bool
    padding_scheme: str

@dataclass(frozen=True)
class CompositionPolicy:
    require_length_mitigation: bool
    require_auth_before_decompress: bool
    allowed_padding_schemes: frozenset[str]

@dataclass(frozen=True)
class CompositionManifest:
    verdict: CompositionVerdict
    directive: str
    manifest_digest: str

class CompressionEncryptionGuard:
    @staticmethod
    def _hash(data: str) -> str:
        return hashlib.sha256(data.encode("utf-8")).hexdigest()

    @classmethod
    def evaluate_config(
        cls, cfg: CompressionEncryptionConfig, policy: CompositionPolicy
    ) -> CompositionManifest:
        
        # Gate 1: Integrated composition bypasses checks
        if cfg.composition_order == "INTEGRATED":
            digest = cls._hash(json.dumps({
                "compression": cfg.compression_algorithm_id,
                "encryption": cfg.encryption_algorithm_id,
                "order": "INTEGRATED"
            }, sort_keys=True))
            return CompositionManifest(
                verdict=CompositionVerdict.SAFE_COMPOSITION,
                directive="PROCEED: Integrated AEAD with compression is safe.",
                manifest_digest=digest
            )

        # Gate 2: Length oracle
        if cfg.composition_order == "COMPRESS_THEN_ENCRYPT" and not cfg.length_leak_mitigation:
            if policy.require_length_mitigation:
                return CompositionManifest(
                    verdict=CompositionVerdict.LENGTH_ORACLE_RISK,
                    directive="HALT: Compress-then-encrypt without length mitigation. Vulnerable to CRIME.",
                    manifest_digest=cls._hash("LENGTH_ORACLE")
                )

        # Gate 3: Decompression bomb
        if cfg.composition_order == "COMPRESS_THEN_ENCRYPT" and not cfg.authenticate_before_decompress:
            if policy.require_auth_before_decompress:
                return CompositionManifest(
                    verdict=CompositionVerdict.DECOMPRESSION_BOMB_RISK,
                    directive="HALT: Decompression before authentication. Vulnerable to compression bombs.",
                    manifest_digest=cls._hash("DECOMPRESSION_BOMB")
                )

        # Gate 4: Padding oracle
        if cfg.padding_scheme not in policy.allowed_padding_schemes:
            return CompositionManifest(
                verdict=CompositionVerdict.PADDING_ORACLE_RISK,
                directive=f"HALT: Padding scheme {cfg.padding_scheme} not in allowlist.",
                manifest_digest=cls._hash(f"PADDING:{cfg.padding_scheme}")
            )

        # Gate 5: Safe
        digest = cls._hash(json.dumps({
            "compression": cfg.compression_algorithm_id,
            "encryption": cfg.encryption_algorithm_id,
            "order": cfg.composition_order,
            "mitigation": cfg.length_leak_mitigation,
            "padding": cfg.padding_scheme
        }, sort_keys=True))
        
        return CompositionManifest(
            verdict=CompositionVerdict.SAFE_COMPOSITION,
            directive="PROCEED: Compression-encryption composition is safe.",
            manifest_digest=digest
        )