C4 Bomb: Blowing Up Chrome’s AppBound Cookie Encryption
In July 2024, Google introduced a new feature to better protect cookies in Chrome: AppBound Cookie Encryption. This new feature was able to disrupt the world of infostealers, forcing the malware developers to quickly modify their malware to adapt to the latest protections. In the new era of cookie protection, infostealer malware either need direct access to the Chrome process or to run with elevated privileges.
In this blog post, we will explore the newly introduced AppBound Encryption and introduce our C4 Attack (Chrome Cookie Cipher Cracker), which allowed us to decrypt the cookies as a low-privileged user. Furthermore, this technique also allowed us to abuse Google’s new security feature to attack Windows machines and access data that should typically only be available to the privileged SYSTEM user.
The research detailed in this blog was performed strictly for responsible and ethical security analysis. All vulnerabilities discovered during this research were responsibly disclosed to Google and Microsoft prior to publication as part of our commitment to contributing to the open source and security community (see “Responsible Disclosure” section below).
Introduction
For many years, Google, along with the rest of the world, have been struggling to secure cookies from theft by infostealer malware. Since Chrome covers a significant share of the browser market — and most other browsers are Chromium-based (e.g., Edge, Opera) — whatever security measures Google has for Chrome, most of the world has too.
Before AppBound Encryption, for infostealer malware to steal cookies on Windows machines they needed to access two files: an SQLite file called Cookies, where the encrypted cookies are stored, and a json file called Local State, which stores a key — one we’ll call the cookie key — necessary to decrypt the cookies. The cookie key is encrypted with the Windows Data Protection API (DPAPI) to further protect cookies from theft. To decrypt the DPAPI encrypted blobs, a process must run in the same user context as the process that encrypted them.
Figure 1. Old cookie protection flow
This older method of protecting cookies might be effective against attackers who steal the cookie file with tools like WinSCP or RClone, but it’s not a very effective solution for malware. Because Chrome runs in the context of a low-privileged user when encrypting the cookie key, any malware running as a low-privileged user can also use the DPAPI to decrypt the cookie key and, subsequently, the cookies. This is why Google introduced a new method for cookie protection.
AppBound Encryption
There are three major changes between the old method of cookie protection and the AppBound method:
Figure 2. AppBound Encryption flow
-
- SYSTEM DPAPI encryption added: A new layer of encryption was added (shown as step 4 in Figure 2). Now, Chrome cookies are encrypted using a key that’s first protected by the user’s DPAPI (User-DPAPI), then encrypted again using the SYSTEM account’s DPAPI (SYSTEM-DPAPI). This means only SYSTEM-level processes can decrypt the cookies, blocking access from low-privileged malware. However, this also causes a new problem: Since Chrome runs as a regular user, it can’t decrypt the cookies on its own anymore.
- Delegate decryption: To solve the new problem, encryption and decryption are delegated to a COM server created by Google called the elevation service (Figure 2 on the right). The elevation service is installed with Chrome and runs as SYSTEM.
In the new setup, Chrome sends the encrypted blob to the elevation service for decryption in a COM request. The elevation service uses DPAPI twice — first with SYSTEM-DPAPI and then User-DPAPI (using token impersonation). The result is the cookie key, which is returned to the requester (Chrome) and can then be used to decrypt the cookies. But this reintroduces the original problem: Since the elevation service is a COM server, any process can send a COM request to the elevation service to decrypt the cookies. - Add path validation data: The third part solves the final issue by comparing the path of the requesting process to some validation data (step 6 in Figure 2). The validation data is the path of the original encrypting process (in our case, Chrome). When Chrome initially creates the cookie key, the elevation service encrypts both the Chrome executable path and the cookie key. Then, when Chrome requests the cookie key, the elevation service compares the path of the requestor to the path from the encryption. Only if the paths match will the elevation service return the key.
Those three features put together comprise the AppBound cookie encryption (see Figure 2). Introducing this feature forced malware developers to change how cookie theft was accomplished, by switching mostly to either running with elevated privileges or extracting the cookies from Chrome’s memory.
Attacking AppBound Encryption
The setup for AppBound cookie encryption is complicated, and it heavily relies on DPAPI, which is very complicated in itself. Seeing as different teams across multiple companies developed both complicated features, there was a greater potential for error, and we felt there was a relatively good chance for a mismatch, resulting in a security issue somewhere in the mix.
We decided to explore AppBound Encryption and see if there might still be ways for low-privileged malware to steal cookies without needing to access Chrome.
There are a lot of promising places to start looking:
- Trying to impersonate Chrome to get the elevation service to give us the key
- Trying to impersonate the elevation service so Chrome encrypts cookies with a key created by the malware
- Eavesdropping on the communication between Chrome and the elevation service to get the cookie key
- A downgrade attack to get Chrome to use the old method of cookie encryption, so a low-privileged malware can also decrypt them
- Finally, though it seemed far-fetched, cracking the encryption
Many variations of these were pretty doable for an admin. For example, creating a malware named chrome-decrypt.exe and saving it in the same folder as Chrome allows impersonating Chrome to get the cookie key from the elevation service (this is possible because part of the path is trimmed when doing the validation). Another example would be to replace the elevation service binary with a malicious one. Similarly, by using the group policy, one can disable AppBound Encryption.
However, we were aiming for low-privileged access, and those ideas required administrative rights. For low-privileged users, we found two effective attacks.
COM Hijacking
The first idea was quick and easy. The elevation service is a COM server. This immediately pushed us to look at COM hijacking as a possibility. Not too surprisingly, the elevation service is (like many COM servers) vulnerable to COM hijacking. Theoretically, an attacker can write a specialized COM server malware to play the role of the elevation service.
Then, every time Chrome opens, the browser sends a request to the malware for the cookie key, and the malware can send any key it chooses. This technique has a bit of a limitation, though, since all the cookies that were encrypted before the COM hijacking will be lost, and an infostealer will have to wait for Chrome to save new cookies with the malware-provided key before they can access them.
Another disadvantage is that creating COM servers can be a lot of work. As it turns out, however, it’s not strictly necessary for this technique. An easier alternative is to point Chrome to a non-existent binary using COM hijacking. If the COM server doesn’t exist, Chrome reverts to using the old encryption method. Again, all old cookies will be lost, so the malware must stay on the machine for a while before the attack bears any fruit.
A demonstration of this attack can be seen in Figure 3. The top part shows before the value is set in the HKCU hive (first row results in NAME NOT FOUND), eventually leading to finding the elevation service binary under HKCR (highlighted row). The bottom part shows what happens after setting the value under HKCU (result is now SUCCESS), which causes Chrome to go looking for a non-existent dll called aaa.dll.
Figure 3. Chrome before (top) and after(bottom) COM hijacking
C4: Chrome Cookie Cipher Cracker
The next attack on the AppBound Encryption is much more interesting from a technical point of view. The attack began as an attempt to try and impersonate Chrome and evolved into something much bigger.
Spoofing with Bit-Flipping Attack – Failed
As a reminder, the elevation service compares the path of the requesting process to the path saved in the validation data. You might think it’s easier to try to impersonate the requestor rather than to try to manipulate the twice AES-encrypted path. But the API used by the elevation service, QueryFullProcessImageName, seems to get the path from the kernel (probably the EPROCESS structure), which isn’t trivial to manipulate.
At the same time, it turns out AES is far less secure than we usually think it to be. As a block cipher, AES is meant to encrypt a single block 16 bytes long. When used for that purpose, AES, as far as anyone can tell, is virtually uncrackable. However, most plaintexts are not exactly 16 bytes long, so we use a combination of “encryption modes” and “padding” to use AES on those varied lengths. While necessary, these features come with many pitfalls that can allow attackers to manipulate plaintexts and potentially even crack the encryption entirely without needing to know the key.
DPAPI uses an encryption mode known as Cipher Block Chaining (CBC), combined with AES, often written as AES-CBC. While AES-CBC is perhaps the most popular encryption mode worldwide, it has many built-in problems.
One such problem is known as the bit-flipping attack. Essentially, each block is decrypted via AES separately, and then the result is XORed with the previous block’s ciphertext (for the first block, an initialization vector is used instead). This is important because it means if an attacker were to take a cipher block Cn , then the next block’s plaintext would change from Pn+1 to Pn+1 ⊕ X Figure 4).
Figure 4. Bit-flipping attack
Though the attack is always possible in CBC, it has limited uses. Normally, an attacker won’t know the plaintext, so modifying it in a predictable way won’t be super useful. Also, by modifying Cn, the block Pn (the plaintext associated with the block Cn) will change unpredictably (Pn* in Figure 4).
Despite the limitations of the bit-flipping attack, in our case, it seemed like a method worth pursuing. Since, in our case, we know part of the plaintext is the path to Chrome. If we could change that path to a location that doesn’t require high privileges to write, we can run a malware from there and bypass the elevation service verification!
In the end, it turned out DPAPI signs its blobs to prevent people from tampering with the ciphertext. When trying to decrypt a DPAPI-encrypted blob that has been tampered with, one can clearly see error messages in the Windows Event Viewer (Figure 5).
Padding Oracle Attack – Success!
While disappointed with our failure, we noticed something strange with the errors in the Windows Event Viewer. Usually, the “reason for failure” was the “MAC check failed” (MAC being the signature), but every so often, the reason was “unknown” instead (see Figure 5). After some inspection, we discovered the difference stemmed from the validity of the plaintext padding.
DPAPI uses PKCS7 padding to ensure the plaintext length is a multiple of 16. If the padding is not in a valid PKCS7 format after decryption, an error is thrown, resulting in the “reason for failure: unknown” message. Only when the padding is valid is the signature checked. Finally, if the signature isn’t valid, the “reason for failure: MAC check failed” message is written.
Figure 5. DPAPI errors in Windows Event Viewer
All the talk about padding might not sound too important at first, but it actually opens the door to an awesome and somewhat rare cryptographic attack known as a “Padding Oracle Attack.” The short version of what the attack does is it allows users to brute force the plaintext of a cipher much more efficiently, allowing the cracking of ciphertexts in a reasonable amount of time.
To implement a Padding Oracle Attack, an attacker needs two things: the ability to modify the end of the plaintext in a predictable way (built into CBC with the bit-flipping attack) and a padding oracle. A padding oracle is a black box that receives a ciphertext and indicates whether the padding of the plaintext is valid (which we get from the event viewer). The attack works by repeatedly sending modified versions of the ciphertext to the padding oracle and tweaking the modifications based on the oracle’s response.
Using the Windows Event Logs as a padding oracle, we were able to implement a Padding Oracle Attack to decrypt the cookies as a low-privileged user. We started by extracting the twice-encrypted DPAPI blob from the Local State file. We then used the Padding Oracle Attack by sending many requests to the elevation service, each with a slightly modified version of the DPAPI encrypted blob. The Padding Oracle Attack allowed us to crack the outermost layer of encryption, effectively bypassing the SYSTEM-DPAPI.
The result was another DPAPI blob, but it was a User-DPAPI encrypted blob this time. Since a low-privileged user encrypted the blob, a simple call to CryptUnprotectData was sufficient to decrypt it. For most Chromium browsers, this would be enough to recover the cookie key.
However, Google added one more step for their Chrome browser called post processing (which is not part of the general Chromium project). We won’t go into full detail here, but in short, there’s some encrypting of the content returned by the CryptUnprotectData with a hardcoded key, followed by some XORs. The result is the cookie key, which we used to decrypt the cookies:
It’s something of a tradition to give Padding Oracle Attacks silly names that are also acronyms describing the attack. The most well-known examples are POODLE, BEAST, and ROBOT. For our attack, since we are cracking a cipher used by Chrome for cookies, we went with C4: Chrome Cookie Cipher Cracker.
Padding Oracle Limitations
While the Padding Oracle Attack was a neat discovery, it has some limitations. The attack seemed to run slowly. Many guesses took more than a second, and the full decryption took around 16 hours. This likely stems from the fact that each guess requires multiple file read/write operations and multiple IPC request responses (some are mentioned in the blog and more come from how CryptUnrptectData works internally). A couple of ideas that might improve the speed include skipping parts when the plaintext is fixed/predictable or trying a timing attack for the padding oracle instead of relying on the events. However, more than likely, the attack would still take several hours.
Another limitation stems from how the brute force is implemented in the Padding Oracle Attack. To try different values in the plaintext for a certain byte, one needs to modify a byte from the previous block. For the first block of plaintext, we need to modify the IV (initialization vector). However, DPAPI uses a fixed IV (all null bytes), preventing an attacker from being able to brute force those first 16 bytes of plaintext.
In the case of cracking Chrome’s cookies, this second limitation isn’t a problem. The plaintext we were trying to reach was itself a DPAPI-encrypted blob (the one encrypted as a low-privileged user). Since the first 20 bytes of DPAPI blobs are fixed, we don’t need to crack them with the Padding Oracle Attack.
Other Uses for the C4 Attack
After a bit of thinking, we realized this attack doesn’t have to be limited to Chrome cookies. In fact, because the elevation service allows a low-privileged user to trigger a decryption attempt of a SYSTEM-encrypted blob, we can crack any SYSTEM-DPAPI blob (subject to the abovementioned limitations). It’s also possible that other programs have the same setup and can be abused to crack blobs encrypted by SYSTEM.
With this in mind, we searched briefly for other potential targets or use cases. Most weren’t especially practical. However, there was a specific case that we think is worth mentioning. As its name suggests, the Windows Credential Manager is used to store credentials. Since storing them in plaintext isn’t a good idea, they are generally encrypted with DPAPI.
Curiously, there seems to be a built-in object stored as a Windows credential belonging to SYSTEM. The object turned out to be a SOAP XML, which contained a user and some authentication token. We are uncertain what it’s used for, as the user seems to be a randomly generated user at the “passport.net” domain rather than the users of the Windows machine. To the best of our understanding, the passport.net domain was used historically for Microsoft single sign on but is no longer in use today.
While the SOAP XML doesn’t have a clear use, we decided to continue with this direction. Any process running as SYSTEM, which stores credentials via the Credential Manager, would likely also encrypt data with DPAPI as SYSTEM. After some searching, we found that the Windows Task Scheduler can be abused this way. The task scheduler can be configured to run tasks even when a user isn’t logged in. To manage this, the credentials must be manually added to the task. Then, the scheduler saves the credentials in the credential manager. Better still, the credentials are saved as part of a bigger object. This means that even though the Padding Oracle Attack cannot decrypt the first bytes, we can still extract the credentials from blobs like this.
Figure 6. Creating task requires credentials stored in the Windows Credential Manager
In the opposite direction, using the task scheduler to crack the encryption of DPAPI blobs is theoretically possible but not at all practical. The task scheduler seems to try to decrypt the blob during the boot process. So, for each guess, an attacker would need to reboot the computer. This would be slow and noisy and require the user to login for each guess, making the attack much worse than the original method abusing the Google elevation service. Even so, this was just one example we found by quickly looking at features. There may be another more practical version of this attack somewhere on Windows.
Summary and Conclusion
Currently, in the form Microsoft built the DPAPI mechanism, any process running as a particular user can decrypt data protected by that same user. However, Microsoft also set it up so that only processes running as that user can decrypt it. Google tried to limit things so that only a single process could access protected data, but this required allowing a low-privileged user to create requests as the SYSTEM user. In doing so, Google ultimately allowed a low-privileged user to crack any SYSTEM-DPAPI blobs.
It was not obvious at all that this would happen, and it took a lot of trial and error to find the issue. However, it shows that when trying to use old features, especially security features, in a new way, one can often end up with unintended problems.
One final thought: According to Wikipedia, CBC is still the most common encryption mode. Considering the issues that come with the encryption mode, perhaps it’s time to start considering CBC insecure and abandon it. The way it was deprecated in TLS after multiple Padding Oracle Attacks repeatedly demonstrated that internet traffic could be cracked.
Special thanks to Dr. Erez Waisbard for the help and guidance when dealing with the cryptography.
Responsible Disclosure
We have reported the issues to both Microsoft and Google. While neither classified the issues as CVEs, Google had stated they would try to fix the Padding Oracle Attack. As of June 23rd, there is a partial solution is Chrome but it’s disabled by default. A full solution will be added in a future release.
Timeline of reports:
COM Hijacking Attack — Google:
- December 3, 2024 – Issue was reported
- December 4, 2024 – Issue was moved to triaged state
- July 2, 2025 – VulnCheck Assigned CVE-2025-34090
Padding Oracle Attack — Google:
- December 4, 2024 – Issue was reported and moved to triaged state
- February 26, 2025 – Issue was moved to accepted state
- July 2, 2025 – VulnCheck Assigned CVE-2025-34091
Padding Oracle Attack — Microsoft:
- March 26, 2025 – Issue was reported
- April 15, 2025 – Microsoft rejected the issue since they concluded that the reported behavior does not meet the criteria for a security fix, citing low practical exploitability due to environmental constraints.
- July 2, 2025 – Though not technically our discovery, was also awarded a CVE in response to this blog: CVE-2025-34092
Ari Novick is a cyber researcher at CyberArk Labs.