Choosing HPKE for Encrypted WAF Payloads
When the Managed Rules team set out to let Enterprise users inspect the exact part of a request that triggered a Firewall Rule, the core challenge wasn't the feature itself—it was securely storing the debugging data. This payload information can contain cookies, personally identifiable information, and other sensitive request components. The design constraint was strict: the user who owns the data must be the only party capable of decrypting it. Cloudflare itself should not be able to read the stored content, treating any PII that transits the network as a toxic asset.
This requirement rules out symmetric encryption, where a single key would give Cloudflare access. The logical path was public key encryption, but choosing an algorithm and implementation required evaluating several dimensions.
Why HPKE?
The evaluation team immediately gravitated toward Hybrid Public Key Encryption (HPKE), which combines the strengths of asymmetric and symmetric cryptography. This hybrid approach boosts performance without sacrificing the security properties of public key encryption. While hybrid schemes have existed in various forms for years, HPKE distinguishes itself by aiming for a single, robust, interoperable standard that pairs a general key encapsulation mechanism with a symmetric encryption algorithm.
HPKE comes from the Crypto Forum Research Group (CFRG) at the IETF, which is the same body that produced RFC 7748 for elliptic curves and informs higher-level protocols such as ODoH and Encrypted Client Hello. Given the established relationship with these standards, and HPKE's co-authorship by a Cloudflare colleague, the choice aligned naturally with the company's support for internet standards.
HPKE works by first translating a Diffie-Hellman key agreement into a Key Encapsulation Mechanism (KEM). The KEM's Encap algorithm creates a symmetric secret and encapsulates it within a public key, so only the holder of the corresponding private key can extract it via Decap. An attacker who intercepts the encapsulation cannot recover the random key. The design mixes this key with an optional info argument and specific cryptographic parameter details, ensuring messages cannot be pulled out of context or replayed maliciously—much like how a phrase from your grandmother carries a different meaning when it comes from your dentist.
Future-Proofing
HPKE is designed to work with any KEM, which makes it ready for post-quantum cryptography—it can accommodate all the NIST finalists for post-quantum public-key encryption without reworking the core protocol. The specification is open and advancing toward RFC status after multiple rounds of expert review at the CFRG. Adoption is already underway in protocols like ODoH, ECH, and Message Layer Security (MLS).
Implementation in Rust
Since HPKE is still maturing, the library ecosystem has few settled options. The reference implementation is in Go, and Cloudflare is also building one in Go for its crypto library, CIRCL. However, the firewall code already running at Cloudflare's edge is largely Rust-based, and Rust caught the team's attention for broader reasons—notably its native primitives and its ability to compile cleanly to WebAssembly (WASM). The team adopted a Rust HPKE implementation that shares code across two surfaces: the edge component that encrypts payloads, and the front-end tools that decrypt them.
Compiling to WASM lets the dashboard UI run the identical decryption logic in the browser. This incurs a small overhead in JavaScript bundle size and computational cost, but that tradeoff beats the effort and security risk of re-implementing HPKE with WebCrypto primitives in JavaScript. Reusing one codebase also avoids subtle divergence between the CLI and the browser experience.
The chosen Rust library had not yet been formally audited. To compensate, the team performed an internal security review, examining the cryptographic primitives and their composition. The audit looked at correct memory zeroing and safe random number generator usage, and no security issues were identified.
Secure User Key Handling
Encrypting on a user's behalf requires a public key, and generating that key pair must happen entirely on the user's side—either through a CLI tool or directly in the dashboard—without any communication with Cloudflare servers. The API explicitly rejects the private key; there is no need and no desire to store or see it.
In the dashboard, when a user supplies a private key for decryption, the key lives only in a temporary JavaScript variable. It is never persisted in the browser. Any action that reloads the page, such as a refresh or navigation, forces the user to supply the key again. This inconvenience is a deliberate tradeoff for stronger security.
Extracting the Matched Data
When a request hits the Layer 7 Firewall, it is evaluated against a series of rulesets written in the wirefilter syntax. For example, a rule might match HTTP/1.1 requests with a path containing a newline followed by a character, or a query string with a NULL byte. Matching such a rule activates a second, special execution phase.
Rather than tagging every accessed field during the initial evaluation—a step that adds noticeable computation overhead—the firewall engine re-executes only the matching rules in a dedicated context that tracks field access. This approach avoids overhead for the majority of requests that match nothing, and keeps re-execution scoped to just the handful of rules that did match, thanks to short-circuiting conditions that skip later parts of an expression.
Consider the rule example with an or condition where the first clause already evaluates to true. The engine tags only http.request.version and http.request.uri.path as accessed fields—the query string field is never touched because evaluation stops early.
The collected fields go through post-processing: subsets of larger fields are removed (for instance, the query string is redundant when the full URI is already captured), and overly long fields are truncated. The final result is serialized as JSON, encrypted with the user's public key, byte-serialized, and prefixed with a version number for future evolution. The API then displays a base64-encoded string of those bytes for consumption.
The encrypted blobs are stored in ClickHouse. Decryption happens fully offline—users either run the CLI tool from cloudflare/matched-data-cli or paste the data into the dashboard UI for in-browser decryption. Because the CLI is open-source and HPKE is an interoperable standard, third-party tools can integrate it into a user's logging pipeline, such as within SIEM software.
The choice of HPKE paid off in both ease of implementation and runtime performance. Its pending standardization and the hybrid approach to key encapsulation and symmetric encryption made it the clear winner for this feature.



