curl · Report #3802645
verify-release rebuilds from the tarball under verification, enabling pre-check command execution and false OK for a malicious curl release tarball
How it was found
Summary:
scripts/verify-release is documented as a way to independently verify a downloaded curl release tarball, but on curl-8.20.0 it extracts the tarball under verification and executes ./configure and ./scripts/dmaketgz before any trust decision is made.
This creates a circular trust failure: attacker-chosen commands from the tarball run in the verifier context before authenticity/integrity is established, and the same malicious tarball can still be reported as curl-8.20.0.tar.gz: OK.
Using a trusted verifier copied from the clean official tag curl-8_20_0, with the tarball as the only attacker-controlled input, I reproduced verifier-side attacker-chosen command execution from a malicious tarball built with curl’s own release tooling.
strace -f -e execve shows execve("./configure", ...) before execve("/usr/bin/sha256sum", ["sha256sum", "-c", "checksum"], ...), while the final result is still curl-8.20.0.tar.gz: OK.
This is a source-package / distribution-integrity issue, not a generic infrastructure issue.
Affected version
Confirmed affected: 8.20.0 source release (curl-8_20_0 tag).
Likely affected: 8.10.0+, because verify-release first shipped in 8.10.0.
Platform used for reproduction:
Linux kali 6.18.12+kali-amd64 #1 SMP PREEMPT_DYNAMIC Kali 6.18.12-1kali1 (2026-02-25) x86_64 GNU/Linux
Steps To Reproduce:
-
Use a clean official curl repository checkout and extract the trusted verifier from the clean release tag:
git show curl-8_20_0:scripts/verify-release > trusted-verify-release && chmod +x trusted-verify-release -
Run the attached PoC
poc_verify_release_trust_failure.shagainst the clean repo. -
The PoC downloads the official
curl-8.20.0.tar.gz, confirms that the official tarball and the clean official tag do not contain the payload marker, injects a safe source-level payload intoconfigure.ac, rebuilds a malicious tarball using the official./scripts/dmaketgz, and then runs the trusted verifier understrace -f -e execve. -
Observe the decisive output:
official_tar_has_payload=notrusted_tag_has_payload=nopre_auth_exec=yesconfigure_execve=...execve("./configure", ["./configure", "--without-ssl", "--without-libpsl"], ...)sha256sum_execve=...execve("/usr/bin/sha256sum", ["sha256sum", "-c", "checksum"], ...)curl-8.20.0.tar.gz: OK
-
Observe the proof file produced by the attacker-chosen payload:
uid=1000 gid=1000 user=nobcodercwd=/tmp/.../curl-8.20.0argv0=./configureHOME=setUSER=setSHELL=setPATH=setGNUPGHOME=unsetSSH_AUTH_SOCK=setGITHUB_VAR_COUNT=0
-
Observe that the malicious tarball accepted by the verifier had SHA-256:
378a4c4de88b2cd55b6933faf1b61ba838130c754938226b4ed0f6716559678c
I have attached:
- the stronger PoC,
- verifier log,
straceexec-order log,- proof file,
- and a ZIP bundle with all evidence.
Impact
Impact:
Summary:
An attacker who can cause a verifier to run curl’s documented verify-release workflow on a malicious release tarball can achieve verifier-side attacker-chosen local command execution before authenticity is established, while the trusted verifier still returns a false successful result (curl-8.20.0.tar.gz: OK).
This breaks the exact release-integrity property curl claims for verify-release: signatures prove origin, while verify-release is presented as the mechanism that should detect a release manager or release host adding extra malicious content to an official release. The current implementation cannot do that because it rebuilds from the tarball being verified.
I did not attempt to access or exfiltrate secrets. My proof only demonstrates execution-context visibility and false verification.