Name constraints are an X.509 extension on a CA certificate that limits which names the CA can issue for, such as hosts under internal.example.com alone. If the CA key leaks, a constrained CA cannot be used to impersonate public sites that clients trust through it.
The problem
When you add a private CA to a trust store, every client that trusts it will accept any certificate it signs, for any name, including a public website. That is a lot of power to give a single file. Name constraints cut it down.
What the standard says
RFC 5280 defines the extension with two lists: permitted subtrees and excluded subtrees. A name matching an excluded subtree is invalid whatever the permitted list says. Conforming CAs must mark the extension critical, and must not issue a certificate where the extension is empty, so at least one of the two lists must be present. Applications conforming to the profile must be able to process constraints on directory names and should be able to process them on email addresses, URIs, DNS names and IP addresses.
The RFC also notes that subject alternative names can be constrained the same way, which matters because modern clients check those names.
An openssl example
In the extensions section used to sign your private issuing CA, add:
[ v3_ca ]
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, keyCertSign, cRLSign
nameConstraints = critical, permitted;DNS:internal.example.com, permitted;DNS:.internal.example.com
The leading dot form covers subdomains. Treat this as a template and test it, because support differs by client.
How to roll it out
- Decide the namespaces the CA should ever cover. Use names you own.
- Issue the constrained CA and keep the root offline, with the constrained issuing CA online.
- Test with every client you care about, including Java, Node, Python, curl and mobile. The RFC says applications should process DNS and IP constraints, not must, so confirm behavior rather than assume it.
- Check you did not lock yourself out. A critical constraint the client does not understand can cause rejection. Better to find that in testing.
- Document it next to the trust distribution steps in how to trust a private CA.
Example scenarios
- Internal platform CA. Permit the internal domain alone, so the CA cannot sign for any public name.
- Per customer CA. Permit one customer namespace per CA, so a leak affects one tenant.
- Device fleet. Permit a device naming domain, and exclude everything else.
What it does not do
It does not protect the key. Keep the root offline and the signing key in a hardware store or protected service, and plan for a leaked private key. It limits the blast radius, it does not replace key hygiene.
Where Safeguard fits
Safeguard scans dependencies and SBOMs for known vulnerabilities, including those in the TLS and crypto libraries your projects pull in, and you can try it with the free scan at gold.safeguard.sh/scan.
Quick check
Do name constraints stop a leaked CA key from being abused?
They limit it to the permitted names for clients that enforce the extension. Protect the key as well.
Must the extension be critical?
RFC 5280 says conforming CAs must mark it critical.
Sources
Last reviewed: 19 October 2026.