The Uploader Nobody Checksummed — Python Bug Hunt
Modelled on the Codecov Bash Uploader compromise (disclosed April 2021): an attacker modified the uploader script Codecov served, and for about two months…
- Language: Python
- Layer: Backend
- Difficulty: Easy
- Concepts: Security, Validation
- Modelled on: Codecov · 2021
- Visible tests: a script matching its checksum runs; a tampered script is refused and never runs
- Reward: 50 XP for a complete fix
Briefing
Modelled on the Codecov Bash Uploader compromise (disclosed April 2021): an attacker modified the uploader script Codecov served, and for about two months CI pipelines that downloaded it and piped it straight into a shell sent their environment variables — credentials included — to a server the attacker controlled. It was noticed when a customer found the script did not match its published checksum.
installer.py downloads the uploader and runs it. It computes the checksum, but a mismatch only produces a warning.
Fix install so a script is run only when its SHA-256 matches the published value.
Bug report
BUG-UPLOADER · Priority: Critical (supply chain) · Reported by: security
install(fetch, published_sha256, run, log):
- script = fetch() (bytes); digest = the SHA-256 hex digest of script
- the published value is compared case-insensitively, surrounding whitespace ignored
- match: call run(script) exactly once, return the digest (lower-case hex), append nothing to log
- mismatch, or a missing/empty published value: append one line starting with "refused:" to log, raise errors.IntegrityError, and never call run
Observed: a tampered uploader logged "warning: checksum mismatch" and ran anyway.
Logs
[ci] fetched codecov uploader (5.2 KB)
[ci] warning: checksum mismatch 9f2c...e1
[ci] running uploaderThe code as shipped
src/ci/installer.py (editable)
import hashlib
errors = bug_require("./errors.py")
def install(fetch, published_sha256, run, log):
script = fetch()
digest = hashlib.sha256(script).hexdigest()
if digest != published_sha256:
log.append("warning: checksum mismatch " + digest)
run(script)
return digest
Read-only context: src/ci/errors.py.
Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More Python bug hunts.