Lion Cipher Lab

Build a TUF-Signed Update Repository From Scratch (and Survive a Compromised Mirror)

Why it matters

Every `pip install`, `apt upgrade`, `docker pull` and silent auto-update is a moment where a remote machine tells your machine what code to run. Signing the package is the obvious defence and it is not enough: a hostile mirror can replay a correctly-signed release that has a known CVE in it, or serve you today's valid metadata forever so you never learn a patch exists, or steal the one key that sits on the always-online signing server. The Update Framework was designed on the assumption that the repository and the network are ALREADY compromised, and it is now the machinery underneath PyPI's…

What you'll learn

Steps in this lab

  1. The question this lab answers: how does a package manager survive a mirror that has already been taken over?
  2. Every word you need, defined, before any code
  3. Set up: one folder, Python, and exactly one dependency
  4. Write tuflib.py — deterministic keys, canonical JSON, and the signature primitive
  5. Write repo.py — the four roles, two releases, and nine mirrors (eight of them hostile)
  6. Read what you just built — snapshot.json is the whole idea in twenty lines
  7. Write client.py — the update workflow, in the order the spec demands
  8. Write attacks.py and get the honest baseline first
  9. Attack 1 — ROLLBACK: a correctly-signed OLD release, to hide a security fix
  10. Attack 2 — FREEZE: serve today's perfectly valid metadata forever
  11. Attack 3 — MIX-AND-MATCH: assemble a repository state that never existed
  12. Attack 4 — ARBITRARY PACKAGE: the attacker owns the online keys and still cannot ship code
  13. Attack 5 and the recovery — forging a rotation, then doing a real one
  14. Why this beats a GPG-signed repository, and where TUF actually ships
  15. The judgment: when NOT to build this, and what to actually carry away

Open the full interactive lab →