Privacy-Preserving Link Safety in Messenger
Messenger’s Safe Browsing feature is designed to protect users from malicious links shared within chats, even when those messages are end-to-end encrypted. While the standard setting relies on on-device models to analyze links, the Advanced Browsing Protection (ABP) setting goes further by checking links against a much larger, continuously updated watchlist of potentially dangerous websites. Building ABP requires a complex combination of infrastructure components and cryptographic techniques. The core challenge is enabling the WhatsApp client to query a server-side blocklist without revealing which URL is being checked, all while maintaining the efficiency needed for real-time chat operations.
The Cryptographic Foundation of ABP
ABP is built on a cryptographic primitive called private information retrieval (PIR). In a classic PIR protocol, a client queries a server to determine whether a specific item exists in the server’s database, while the server learns nothing about the subject of the query. In a purely theoretical setting, the server could solve this by simply sending the entire database to the client once. The client could then perform unlimited local queries. However, this isn’t practical for ABP for two reasons:
- The blocklist database is too large and must be updated frequently, making full downloads impossible.
- Revealing the entire blocklist to clients could help attackers understand how to circumvent the system.
Prior research has proposed improving on this using an oblivious pseudorandom function (OPRF) combined with splitting the database into multiple shards, or “buckets.” This way, the client only needs to perform a linear-time scan over a fraction of the database. This approach served as the starting point for ABP, but required adaptation to fit the unique constraints of URL matching.
A standard OPRF handles exact-match queries well, but that’s not how URL-based lookups work. The client and server don’t always have identical strings. For example, if the blocklist contains example.com, but the client queries example.com/a/b/index.html, it should still count as a match. Privacy is the fundamental difference between ABP’s use of OPRF and other use cases that have been explored in prior literature.
Another complication arises with sharding itself: the client must disclose which bucket it wants to query, which inherently leaks some information. Smaller buckets offer greater efficiency but reveal more about the query. Larger buckets protect privacy better but degrade performance. While some proposed cryptographic constructions using lattice-based techniques could reduce the need for sharding, they were not practical enough at this scale at the time ABP was built.
Addressing Prefix Queries on URLs
One naive approach to prefix matching would be to run a separate PIR query for every possible path prefix of a given URL. For a link like example.com/a/b/index.html, this would mean four separate queries:
example.comexample.com/aexample.com/a/bexample.com/a/b/index.html
This approach would function, but it significantly increases privacy risk. If the underlying PIR scheme leaks B bits of information to the server, then this scheme leaks P * B bits, where P is the number of path prefixes. For long URLs, this leakage could be enough to identify the full, unencrypted link.
To reduce leakage, the server can group links by domain into a single bucket. The client then requests only the bucket that matches the query link’s domain and performs all prefix checks locally within that bucket. This ensures the server learns at most B bits of information. This introduces a critical performance challenge. When URLs are hashed into buckets, they tend to distribute evenly as long as full URLs are used as inputs. However, hashing only domains produces highly uneven bucket sizes. A malicious link-shortening service, for example, may host thousands of URLs that all share one domain, causing massive bucket overflow. Since all buckets must be padded to the size of the largest one, having one oversized bucket can drastically inflate response sizes for every query.
Generating Custom Rulesets Before Lookup
To solve the bucket imbalance problem, the server performs a preprocessing step to create a “ruleset.” This ruleset is a list of instructions clients use to determine which bucket a given URL belongs to. It is pre-computed by the server and shared with clients in advance, so clients can apply the rules locally at lookup time. As an example, a simple ruleset consists of rules mapping an 8-byte hash prefix to a number of additional path segments. When a query link arrives, the client computes the hash of the domain and checks whether the result aligns with a rule in the ruleset. If it matches, the client appends that many path segments from the URL to the domain, re-hashes the combined value, and again checks for a new rule. This process continues until no rule applies, at which point the hash prefix becomes the bucket identifier.
| Hash Prefix | # of Path Segments |
| 08bd4dd11758b503 | 2 |
| fe891588d205cf7f | 1 |
| c078e5ff2e262830 | 4 |
The server constructs this ruleset iteratively. It starts by assuming every URL is hashed on the domain alone and divides the database into initial buckets. It then identifies the largest bucket, finds the most common domain within it, and introduces a new rule to split that domain into several smaller buckets using path segments. This loop continues until every bucket falls below a configured size threshold. This approach guarantees that any URL containing a blocked prefix maps to the bucket holding that entry. That invariant depends on the blocklist being free of redundant entries, where one entry is a prefix of another, and on a hash function that won’t cause collisions among blocklist entries.
At query time, the client applies the same ruleset to the incoming link. It generates a bucket identifier, then sends that identifier to the server along with an OPRF-blinded request for each path segment of the local URL. The server responds with the appropriate bucket plus OPRF responses. The client unblinds these results, scans for an exact match, and flags the link if one is discovered. The protocol masks two critical side channels. The number of elements included in the client’s request must be padded to a uniform maximum so the server can’t infer URL lengths. Bucket contents similarly need uniform padding so the response size doesn’t hint at what kind of link is being queried. Both fields must remain constant across queries to preserve privacy.
Shielding Queries from the Server
Even with the bucket-based design, the client still sends a bucket identifier derived from the URL to the server. To minimize what a compromised or adversarial server could infer from that identifier, Advanced Browsing Protection (ABP) layers on two additional protections: confidential computing and oblivious access patterns.
Confidential Computing with AMD SEV-SNP
To keep hash prefixes from being exposed on Meta's servers in plaintext, ABP runs the bucket lookup logic inside a confidential virtual machine (CVM) backed by AMD's SEV-SNP technology. The CVM provides a trusted execution environment (TEE) that can generate attestation reports, which clients can verify before trusting the environment with their data.
An attestation report contains the following elements:
- A container manifest with hash digests of the CVM's launch configuration and packages, serving as a commitment to the application logic running inside.
- A public key generated at CVM startup, paired with a private key that never leaves the TEE.
- A certificate chain rooted at AMD's Key Distribution Service.
- A signature from a transparency log witness, providing a uniqueness guarantee that prevents server-side equivocation.
After verifying the report's certificates and signatures, the client uses the embedded public key to establish a secure channel to the CVM. The encrypted bucket identifier is sent over this channel, and the CVM decrypts it to perform the lookup. The hardware setup closely follows the approach Meta previously described for WhatsApp Private Processing.
One gap remains: the attestation artifacts have not yet been released for external security researchers to audit. Meta aims to provide a hosting platform for these artifacts in the near future.
Oblivious RAM
AMD SEV-SNP encrypts memory pages via Secure Nested Paging (SNP), but encryption alone does not hide memory access patterns. An adversary with administrative access to the host system could still observe which buckets are fetched over time. To address this, the server must ensure that memory access patterns do not reveal which bucket is being read.
The most direct countermeasure is loading the entire database into memory at startup and, for every client request, retrieving all B buckets even though only one is used in the response. This linear scan eliminates the leak but is wasteful: the B-1 unused accesses add significant overhead, especially for large databases. Two techniques reduce this cost without weakening privacy:
- Because the database is not overwhelmingly large, multiple independent copies can reside in memory on a single machine. Incoming requests are assigned to an available copy, since the linear scan is inherently sequential.
- Asymptotic improvements—from linear to sublinear access—are possible using Path ORAM, an algorithm whose details in this context are covered in Meta's open-source ORAM library.
Oblivious HTTP
A final layer of protection comes from a third-party proxy implementing the Oblivious HTTP (OHTTP) protocol. The proxy sits between the client and server: it strips identifying information such as the client's IP address from encrypted requests and forwards the de-identified payload to the server, which can then decrypt it. This separation makes it harder for the server to correlate requests with specific clients.
The ABP Request Lifecycle
Putting these components together, ABP operates in two phases.
Pre-processing and background phase:
- On a periodic basis, the server pulls the latest URL database updates and computes a ruleset that balances entries into similarly-sized buckets.
- Buckets are loaded onto a TEE using ORAM.
- The TEE generates a keypair; the public key is embedded in an attestation report from AMD SEV-SNP hardware.
- The attestation report and current ruleset are provided to the client through a third-party proxy.
- The client verifies the report's signatures and stores a local copy of the public key and ruleset.
Per link click:
- When a user clicks a link in an end-to-end encrypted chat, the client applies the ruleset to compute the URL's bucket identifier.
- The bucket identifier is encrypted for the specific CVM instance using its public key.
- The client also computes a set of OPRF requests (blinded group elements), one for each padded path segment of the URL.
- The encrypted bucket identifier and OPRF requests are sent via a third-party proxy to the server, along with a client public key to establish a secure channel.
- The server precomputes its side of the OPRF evaluations.
- The server decrypts the bucket identifier, uses ORAM to retrieve the corresponding bucket's contents, and returns the OPRF responses and bucket contents to the client, encrypted under the client's public key.
- The client decrypts the response, completes the OPRF evaluation using the bucket contents, and checks for a match. If one is found, the client displays a warning about the link.



