Twelve unauthorized TLS certificates were issued for 1.1.1.1 — the IP address half the internet uses as its DNS resolver — starting in February 2024, and nobody noticed for nineteen months. The issuing CA was Fina RDC 2020, trusted by Windows and Edge through the Microsoft Root Program, and the disclosure only landed in September 2025 when a researcher found the certificates in transparency logs. Nothing about the victim's infrastructure was breached. A certificate authority the victim never chose simply issued for a name it never validated, and every client that trusted that root would have accepted the result.
That incident is the entire argument for Certificate Authority Authorization in one paragraph: if you do not name which CAs may issue for your domain, you have authorized all hundred-plus of them.
And there is now a deadline attached. CA/Browser Forum ballot SC-098v2, passed in May 2026, requires every publicly trusted CA to honor the RFC 8657 CAA parameters — accounturi and validationmethods — starting March 15, 2027. For a platform that issues tenant certificates automatically, the next six months are the window to document the strict form of CAA before the ecosystem assumes it. Here is the record set, what each line constrains, and how to ship it without breaking your own renewals.
The record set, up front
This is the core deliverable: the CAA set a tenant domain should publish when a self-hosted PaaS issues its certificates through one Let's Encrypt ACME account. Replace YOUR-ACCT-ID with the platform's account number and security@ with a mailbox someone reads:
example.com. CAA 0 issue "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/YOUR-ACCT-ID; validationmethods=dns-01"
example.com. CAA 0 issuewild ";"
example.com. CAA 0 iodef "mailto:security@example.com"Three lines, three jobs. The issue record says only Let's Encrypt may issue ordinary certificates, only through your platform's ACME account, and only when control is proven over DNS. The issuewild ";" record refuses wildcard issuance outright — the lone semicolon is the RFC's explicit "nobody" value, and a PaaS issuing per-tenant hostnames has no business minting wildcards. The iodef record gives compliant CAs an address to report policy violations to, so a refused issuance attempt becomes a security email instead of a silent log line.
Note what is deliberately absent: there is no second CA in this set. If your platform also issues through ZeroSSL or Google as a fallback, each of those needs its own issue line or the fallback breaks the day you need it. Pinning is a complete enumeration of your issuance paths, not a preference list.
What each line actually constrains
CAA works in narrowing layers, and each layer stops a different attacker. Read the table bottom-up: every row assumes the rows below it are already in place.
| Attacker capability | What stops them | Which parameter |
|---|---|---|
| Any of ~100 public CAs issues for your domain after a validation slip | Allow-listing one CA | issue "letsencrypt.org" |
| Attacker passes domain validation at your CA through their own account (brief DNS hijack, dangling record) | Binding issuance to your account key | accounturi=https://…/acct/… |
| Attacker steers validation to a weaker proof (HTTP file drop on a compromised origin) | Restricting the proof to DNS | validationmethods=dns-01 |
| Nobody notices the attempt | Violation reports to your inbox | iodef "mailto:…" |
Two honest limits before anyone treats this as magic. First, CAA binds compliant CAs: it is a Baseline Requirements obligation to check, and a CA that skips the check or validates sloppily — the Fina pattern — is caught by Certificate Transparency monitoring, not by CAA. Defense in depth means publishing CAA and watching CT logs for your domains.
Second, accounturi proves possession of the ACME account key, so it is only as strong as your key custody: an attacker who steals the platform's account key passes the pin. The pin converts "hijack DNS for five minutes" into "hijack DNS and steal a private key," which is a much harder attack, not an impossible one.
The validationmethods row deserves one extra sentence. Pairing dns-01 with DNSSEC gives you a cryptographically strong validation path end to end: signed DNS answers proving control, consumed by the one account allowed to present them. Leaving http-01 enabled keeps a weaker proof alive on every origin server you run — and origins get compromised far more often than DNSSEC-signed zones.
What the big platforms tell tenants (and what they don't)
Netlify is the positive example the rest of the industry should copy. Its HTTPS documentation publishes the platform's real Let's Encrypt account URI and tells tenants, nearly verbatim, that adding a CAA record with that accounturi ensures only Netlify can create Let's Encrypt certificates for the custom domain. One documented URI, one copy-paste record, tenant-side enforcement with zero platform code changes. If you operate a PaaS, that docs paragraph is the entire feature.
Most other platforms stay quieter, and the reasons are operational rather than sinister. Cloudflare auto-adds broad CAA records (plain issue "letsencrypt.org", no accounturi) so Universal SSL keeps working across its multi-CA issuance fleet — pinning to one account would fight a design where different CAs issue different edge certificates on different days. Tenant-authored restrictive CAA is a recurring cause of "issuance stuck" support tickets there.
Vercel carries CAA records on its cname.vercel-dns-017.com targets instead of asking tenants to publish anything, which works precisely because CAA lookups follow CNAMEs — a detail with a sharp edge, covered below. The general pattern: platforms that issue through several CAs, rotate accounts freely, or absorb DNS support load from non-technical tenants rationally choose the loose default and eat the residual risk.
A self-hosted PaaS gets to make the opposite trade. You issue through one ACME account you control, your tenants are technical enough to paste three DNS records, and your support queue is your own. Documenting the strict set costs a docs page and buys every tenant a smaller issuance surface. The platforms that don't do this mostly can't, not cheaply — you can.
The operator checklist
Five items, in dependency order. Do them once and they hold until your issuance architecture changes.
1. Publish your ACME account URI in your tenant docs. The URI is the account URL your ACME client received at registration, of the form https://acme-v02.api.letsencrypt.org/acme/acct/NNNNNNN. If you no longer have it on hand, query the new-account endpoint with onlyReturnExisting set and the server returns the existing account URL. Treat that URI as public configuration, like a DNS name — its secrecy adds nothing, since authorization is proven by the account key, not by knowing the URL. Netlify's URI is in its public docs; yours should be too.
2. Plan rotation as overlapping records, not edited ones. RFC 8657 has a rule that bites during key rollover: a single property containing multiple accounturi parameters is unsatisfiable, and a property with an invalid URI fails closed against you. The correct rotation is two separate issue records — old URI and new URI — with OR semantics across records: either account may issue while both lines exist. Publish the new line, roll the account key, confirm a renewal succeeds under the new account, then remove the old line. Never edit the one record in place and hope the timing works out; DNS propagation plus CA-side caching turns "hope" into an outage.
3. Mind the CNAME bypass. CAA lookups follow CNAMEs, and a CAA set on the target overrides the tenant's own records. Concretely: if www.example.com is a CNAME to your platform's routing hostname and that hostname carries its own CAA records, the tenant's carefully pinned apex records do not apply to www at all. Either keep your routing targets free of CAA records (so the lookup falls through to the tenant's zone) or publish the strict set on the targets yourself and document that tenants inherit it. Audit this with dig from outside your network before you write the docs, not after a tenant asks why pinning "didn't work."
4. Pin every issuance path or none. Staging environments are the classic miss: the Let's Encrypt staging ACME server mints different account URIs under acme-staging-v02, so a tenant record pinned to your production URI blocks staging issuance — which is usually what you want, until the day you debug against staging and conclude the CA is broken. Worse is the fallback CA: if your renewal pipeline fails over from Let's Encrypt to a second CA, a tenant set naming only Let's Encrypt converts a CA incident into your incident. Enumerate production, staging, and fallback accounts in the docs, with one issue line each.
5. Test before you enforce, and watch the mailbox. A wrong accounturi produces no error at publish time — DNS accepts any string, and nothing validates the pin until the next issuance tries to satisfy it. After publishing, force an early renewal (or issue for a scratch subdomain under the same policy) and confirm success while the old certificate is still valid. And actually monitor the iodef mailbox: it only receives reports from CAs polite enough to send them, but a blocked-issuance notice arriving days before expiry is the cheapest early warning in TLS operations.
How a wrong record silently breaks renewal
Every failure mode in this section shares one property: the mistake is made today and the symptom arrives at renewal time, weeks later, when the certificate is already close to expiry. Under the 47-day certificate lifetimes now rolling out across the ecosystem, "weeks later" keeps getting shorter, and the margin between "noticed" and "expired" shrinks with it.
Typo in the URI fails closed. RFC 8657 is explicit: an unrecognized accounturi makes the property unsatisfiable, and with no satisfiable property the CA must refuse. There is no "close enough" matching and no warning issuance. Copy the URI from the ACME server response, never retype it, and validate with a forced renewal the same day.
CNAME shadowing voids the tenant's set. As section 4 noted, this one fails open instead of closed: the tenant believes they are pinned while issuance actually evaluates against the platform target's records. The symptom is not an outage but a false sense of enforcement — arguably worse, because nothing ever pages. The fix is the audit in checklist item 3.
Staging/production URI mismatch. The staging and production ACME directories are different account namespaces. Records pinned to production URIs correctly refuse staging orders, which reads as breakage during every staging rehearsal. Document both URIs, label them loudly, and keep a non-pinned scratch subdomain for staging drills.
Single-CA pinning vs. fallback issuance. This is the failure mode that only appears during someone else's incident: your primary CA has an outage, your pipeline fails over to the backup CA, and every pinned tenant domain refuses the backup's certificates. If you operate a fallback path, its issue line belongs in the documented set from day one — a fallback you cannot use is not a fallback.
None of these is an argument against pinning. Each is an argument against pinning casually: publish deliberately, verify with a live renewal, and re-verify whenever your issuance architecture changes.
The six-month window
March 15, 2027 is when accounturi and validationmethods stop being a Let's Encrypt-and-friends courtesy and become a Baseline Requirements obligation on every public CA. Between now and then, the records you publish are honored by the CAs that already support them and ignored by the stragglers — strictly better than nothing, and exactly the posture to be in when the mandate flips.
If you hold a custom domain on someone else's platform: check whether your platform publishes an ACME account URI (Netlify does), publish the three-line set if it does, and ask support for the URI if it doesn't. If you operate the platform: publish the URI, write the docs paragraph, audit your CNAME targets, and rehearse a rotation before a compromise forces you to improvise one. Twelve certificates for 1.1.1.1 went unnoticed for nineteen months because nothing constrained who could issue for that name. Three DNS records is a cheap way to make sure the next disclosure isn't about yours.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.



