A story about a cool vulnerability I found in vendor code (evervault) while doing an audit.

Some applications (especially web3 related) have really strong security requirements. Think applications handling private keys for L2’s, bridges, multi-sigs or applications that handle super sensitive (medical) data. Companies running such applications can reach for secure enclaves to mitigate a whole range of attack vectors related to operator and server compromise. The core feature of enclaves is that you can verify the code that’s running to make sure your data is processed correctly.

The bug I found had to do with a mistake in client side validation that has clients mistakenly accept malicious enclaves that do not 100% match the desired conditions.

Enclaves

A secure enclave provider (like AWS Nitro) runs containers in a very locked down environment where you can be sure of the code running in your container.

Secure enclaves are very limited, no internet for example, and you can only interact with the container through a virtual socket. Each enclave also comes with an attestation document, which allows an external actor (client) to verify different aspects about the code running in the secure enclave. These different aspects are encoded in so-called PCR values. For example, you can verify the hash of the container image that is running (PCR0), a hash which tells us about the kernel (PCR1) and a hash which informs us whether and by whom the image was signed (PCR8).

This post is too small to provide a deep dive into secure enclaves and TEE, I can recommend the TEE security handbook if you're looking to learn more.

Secure enclaves are great because you can verify exactly what’s running in the enclave before you send any sensitive data to it (like your private key or a MEV bundle).

Evervault

Evervault is a platform that makes AWS Nitro enclaves a lot easier to work with by providing the scaffolding and infrastructure to allow you to connect to an enclave using a simple https connection.

They do so with a neat trick that leverages tls. In short, they simply attach the attestation document to the tls handshake. A client connecting to the secure enclave can use the document to check that the key used to establish the connection to the enclave matches that in the attestation document.

Now the most critical part of an application that leverages secure enclaves is proper checking of the PCR values. Each missed PCR value comes with it’s own set of attack possibilities that are opened up. The bug I discovered was in the validation of the provided PCR values allowing an attacker to force clients to skip checking certain PCR values.

As a result some of the attack vectors that secure enclaves protect against became possible again.

The Bug

Not all users of secure enclaves want to check all PCR values, e.g. you might only want to check that the enclave image is properly signed.

The evervault-go library has a neat feature in it’s interface. You’re allowed to input empty strings as you’re specifying the expected PCR values. Only want to check PCR8? No problem, you can just put empty strings for all the others.

// we'll only have pcr 8 checked in the following example
expectedPCRs := []attestation.PCRs{ 
	attestation.PCRs{
		PCR0: "",
		PCR1: "",
		PCR2: "",
		PCR8: "deadbeef",
	},
}
v := verifyPCRs(expectedPCRs, actualDocument)

The function that compares the expected PCR values to the actual values makes this possible.

// prcEqual Checks if 2 PCR strings are not equal.
func pcrNotEqual(p1, p2 string) bool {
	return p1 != "" && p2 != "" && p1 != p2
}
 
// Check if two PCRs are equal to each other.
func (p *PCRs) Equal(pcrs PCRs) bool {
	if pcrNotEqual(p.PCR0, pcrs.PCR0) {
		return false
	}
 
	if pcrNotEqual(p.PCR1, pcrs.PCR1) {
		return false
	}
 
	if pcrNotEqual(p.PCR2, pcrs.PCR2) {
		return false
	}
 
	if pcrNotEqual(p.PCR8, pcrs.PCR8) {
		return false
	}
 
	return true
}

You might have already spotted the problem by now!

The pcrNotEqual function treats both the user input (trusted) and the external document (untrusted) equally. A malicious host could have empty strings for the PCR values and the code would consider these as automatically okay, even if the user has provided an expected value.

Luckily attackers can’t just send you an empty attestation document. For one, the standard requires at least one PCR value to be set (though it does not have to be one of 0,1,2 or 8). More importantly, any attestation document with a valid AWS signature should have values PCR0-2 present. As a result an attacker should only be able to get their hands on an attestation document that’s lacking the PCR8 value (which attests to the signature of the image, if present).

Conclusion

The evervault team was quite fast in resolving the vulnerability and released a fix within a week followed by a CVE + advisory a bit later(CVE-2025-64186).

If you were affected by this bug then you should upgrade your dependency and consider validating more PCR values. This is worthwhile in any case as each additional PCR value covers more of the attack surface of your secure enclaves.

Overall I think this was an interesting vulnerability to stumble across, and I believe this story highlights the importance of auditing supporting technology in addition to having your own code audited.

Disclosure No rubber ducks were debugged in the process of writing this article.