ASVS 5.0 V6.7.1 says the certificates your application uses to verify cryptographic authentication assertions must be stored in a way that protects them from modification. It is a Level 3 requirement.
Why it matters
If an attacker can replace the trusted certificate, they can sign assertions that your application accepts. Swapping one file or one database row turns signature checks into a rubber stamp for the attacker.
How to implement it
Store trust anchors where application code and ordinary operators cannot rewrite them.
- Keep certificates in a read only location, baked into the image or mounted read only, with file permissions limited to a service account.
- Prefer a managed secret or key store with write access restricted to a small deployment role and audited.
- Pin by fingerprint. Record the expected SHA-256 and compare at load.
- Control change through code review and deployment, not an admin form.
import hashlib
EXPECTED_SHA256 = "replace with the fingerprint from your change record"
def load_trusted_cert(path="/etc/app/idp-signing.pem") -> bytes:
data = open(path, "rb").read()
if hashlib.sha256(data).hexdigest() != EXPECTED_SHA256:
raise RuntimeError("Trusted certificate does not match the pinned fingerprint")
return data
When the IdP rotates keys, update the pin through the normal release path.
How to test it
- Try to write to the certificate location as the application user. It must fail.
- Modify the file in a test environment and confirm the service refuses to start or trust it.
- Review who can change the store and whether changes are logged.
Common mistakes
- Certificates in a writable upload directory or database table editable from the app.
- Fetching verification keys from a URL supplied in the assertion itself.
- No record of who changed the trusted set.
Quick check
Is fetching the IdP's key set from its published metadata URL a problem?
Only if the URL can be changed by an attacker or the transport is not verified. Fix the URL in configuration and require TLS.