Most software updaters trust a single signing key and a single repository, so whoever steals that key or controls that server can push anything to every client. The Update Framework (TUF) is a specification for update systems designed to stay safe even when the repository or some signing keys are compromised: it separates trust into roles with their own keys and thresholds, signs metadata rather than just files, and makes clients detect rollback, freeze and mix-and-match attacks. This guide explains TUF's roles and threat model, how the client verifies updates, how real deployments such as Sigstore's root of trust operate, how to design keys and expiry times, and how to adopt it. It is for engineers building package managers, plugin and model distribution, device and agent updaters, and for security architects assessing them. Firmware and vehicle variants are covered in the IoT Secure Firmware Update Guide (SUIT, signed OTA) and the Automotive Cybersecurity Guide.
Key takeaways
- TUF assumes compromise. Its goal is that an attacker who controls the repository or fewer than a threshold of keys still cannot make clients install arbitrary or outdated software.
- Four top-level roles split the trust. Root, targets, snapshot and timestamp each sign a different metadata file with their own keys, so an online key compromise is far less serious than an offline one.
- Expiry and version numbers do the defensive work. Signed expiry dates stop indefinite freezes, monotonic versions stop rollbacks, and snapshot metadata stops mix-and-match.
- It is in production at scale. Sigstore distributes its trust root through a TUF repository run with tuf-on-ci, and Python's PEP 458 (status Accepted) specifies TUF for PyPI.
- Keys and ceremonies are the hard part. The code is available as reference implementations; the operational work is offline root keys, thresholds, signing events and expiry monitoring.
What TUF is and what it protects against
The TUF specification (version 1.0.37 dated 8 October 2026 when checked on 27 October 2026, maintained in the theupdateframework/specification repository) defines a framework for securing software update systems. TUF is hosted by the Linux Foundation as part of the Cloud Native Computing Foundation. It does not replace a package format or a transport; it adds signed metadata and a client verification workflow on top of whatever repository you already have. The specification lists the attacks it is designed to defeat:
| Attack (TUF name) | What the attacker tries | TUF mechanism that stops it |
|---|---|---|
| Arbitrary installation | Serve any file in response to a download | Targets metadata lists hashes and lengths, signed by a threshold of keys |
| Rollback | Serve an older, vulnerable version the client already moved past | Clients reject metadata with a lower version number than they hold |
| Indefinite freeze | Keep serving old metadata so the client never sees updates | Every metadata file has a signed expiry; the timestamp role expires quickly |
| Fast-forward | Inflate version numbers so legitimate future updates look like rollbacks | Recovery by rotating timestamp and snapshot keys, which makes clients discard the inflated metadata |
| Mix-and-match | Combine metadata files that never coexisted on the repository | Snapshot metadata lists the versions of all targets metadata at one moment |
| Endless data | Send enormous responses to exhaust the client | Metadata records file lengths; clients cap download sizes |
| Extraneous dependencies and wrong software | Make the client fetch unintended dependencies or a different file than requested | Targets and delegations bind each path to its hash and to the role trusted for it |
| Key compromise | Use one stolen key to sign a malicious update | Separate keys per role and signature thresholds; root rotation revokes compromised keys |
| Malicious mirrors | Use a bad mirror to block updates from good ones | Mirrors are untrusted; content is verified against signed metadata |
The specification is candid about limits: an attacker who can intercept traffic can always deny service, but TUF must detect that the client cannot update. And if attackers compromise a threshold of keys, the best TUF can do is limit how many users are affected, which depends on how the deployment separated its keys.
TUF also does not decide whether the software itself is benign. If the build system is compromised and produces a malicious artefact that is then properly signed and published, TUF will faithfully deliver it, as the SolarWinds Supply Chain Compromise showed for signed updates generally. Pair TUF with build provenance; see the SLSA and Build Provenance Guide.
The roles and their metadata
TUF defines four fundamental top-level roles and one optional role. Each role can have several keys and a threshold: metadata is trusted only when signed by at least that many distinct keys.
| Role | Metadata file | What it signs | Key storage per the spec | Typical expiry (PEP 458 example) |
|---|---|---|---|---|
| Root | root.json | The keys and thresholds for every top-level role, including itself | Offline, very secure; shipped with the client | One year |
| Targets | targets.json and delegated role files | Hashes and lengths of target files, and delegations of trust to other roles | Offline (delegated roles may be online) | One year |
| Snapshot | snapshot.json | The current version of every targets metadata file | Can be online | One day |
| Timestamp | timestamp.json | The current snapshot version, re-signed frequently | Online, automated | One day |
| Mirrors (optional) | mirrors.json | List of mirrors | Online | Deployment specific |
- Root: the client must ship with trusted root keys for each repository. The specification says root keys must be kept very secure and should be offline, and that if a threshold of root keys is compromised it is safest to assume attackers have taken over affected machines, because recovery is nearly impossible.
- Delegation: the targets role can delegate full or partial trust (for example, only paths under one project) to other roles, which can delegate further. Revoking a delegation means signing new metadata without it. This is how a repository can give each project or publisher its own keys.
- Timestamp: the specification notes that although the timestamp key must stay online, compromising it poses minimal risk to clients: it can only re-assert existing snapshot metadata until the short expiry runs out.
- Consistent snapshots: repositories can publish metadata and targets under version or hash-prefixed names so clients always fetch a coherent set even while the repository is being updated.
How a TUF client verifies an update
The specification's detailed client workflow is strict and ordered. Implementers should use a conformant library rather than reimplementing it, but reviewers need to know what each step guarantees.
- Fix the update start time: record it once, so expiry checks are consistent for the whole update.
- Load the trusted root shipped with the software (its expiry does not matter yet).
- Walk the root chain: download
N+1.root.json,N+2.root.jsonand so on, with a byte limit on each. Each new root must be signed by a threshold of keys from the previous root and a threshold from itself, each key counted once, and its version must be exactly N+1. This lets an old client follow years of key rotations safely. - Check for a freeze: abort if the final root has expired.
- Recover from fast-forward: if timestamp or snapshot keys were rotated, delete the locally stored timestamp and snapshot metadata.
- Update timestamp, then snapshot, then targets: each must be signed by its role's threshold, not older than the stored version, and unexpired; snapshot must match the hash or version that timestamp declared, and targets must match snapshot.
- Resolve delegations in order to find the role trusted for the requested path.
- Fetch the target and verify its length and hashes against the trusted targets metadata before use.
The specification adds a resilience rule: a failed step should abort the update without leaving the client in an unrecoverable state, so the next attempt can succeed once the repository is fixed.
TUF in production
- Sigstore root of trust: the
sigstore/root-signingproject maintains the TUF repository that delivers Sigstore'strusted_root.jsonto clients such as cosign, published attuf-repo-cdn.sigstore.dev. Changes require signatures from named community keyholders using personal hardware keys during "signing events" run as pull requests, while online signing with cloud KMS keys happens at least every three days because online signatures expire. Changes are tested in a separate staging repository and a preproduction deployment before production. See the Sigstore Guide. - tuf-on-ci: a TUF repository and signing tool that runs on a CI platform, supports hardware keys and Sigstore signing, automated online signing on Google Cloud, Azure, AWS and Sigstore, and threshold delegations. Its documentation states that even a fully compromised repository host will not lead to compromised clients. Besides Sigstore, it lists GitHub's TUF repository for Artifact Attestations as a deployment.
- PyPI (PEP 458): PEP 458, "Secure PyPI downloads with signed repository metadata", is a Standards Track PEP with status Accepted. It specifies online-key signing of all projects through
bin-ndelegated roles under an offlinebinsrole, one-year expiry for root, targets and bins, one-day expiry for timestamp, snapshot and bin-n, and hash-prefix "bins" (16,384 in its analysis) to keep metadata small. This guide does not state how far PyPI's deployment has progressed; check the current PyPI documentation. - Vehicles: Uptane, a TUF variant, is used to secure over-the-air updates for vehicles, as the python-tuf project notes.
- Implementations: python-tuf is the reference implementation (metadata API,
tuf.ngclientclient, and a repository library not yet part of its stable API), and the project lists other adopters on its adoptions page.
Designing keys, thresholds and expiry
Choosing the key layout is the single most important TUF design decision, because it determines what each compromise costs.
| Decision | Small project or internal updater | Large public repository |
|---|---|---|
| Root keys | 3 hardware keys held by different people, threshold 2 | 5 or more keyholders, threshold 3 or more, documented ceremonies |
| Targets | Offline, same keyholders as root or a subset | Offline top-level; per-project or per-publisher delegations |
| Snapshot and timestamp | Cloud KMS keys used by CI | Separate KMS keys per role, with tight IAM on who can sign |
| Expiry | Root and targets 6 to 12 months; timestamp 1 to 3 days | As left, with automated re-signing well before expiry |
| Tooling | tuf-on-ci or an equivalent CI-driven repository | Custom repository service on a conformant library, plus staging |
- Never one key for everything: the specification allows a single-key setup for flexibility but calls it insecure.
- Short timestamp expiry is the freeze defence: the shorter it is, the sooner clients notice that a mirror or attacker is withholding updates, at the cost of needing reliable automated re-signing.
- Root rotation: sign the new root with both old and new root keys, publish it as a numbered file (for example
3.root.json), and let clients walk the chain. - Delegated developer keys: where publishers sign their own targets, a stolen publishing credential alone is no longer enough to ship a release. The Shai-Hulud npm worm spread by reusing stolen npm publishing tokens, the single-online-credential failure TUF's role separation and thresholds are designed to remove.
Adopting TUF
- Define the threat model: list who can currently push updates, which keys and tokens allow it, and which compromise would reach every client. That is the baseline TUF should beat.
- Pick a conformant implementation for the client language and a repository approach (tuf-on-ci for low to moderate change rates, a repository service for high-volume publishing).
- Run a key ceremony: generate root and targets keys on hardware tokens held by separate people, record key IDs and thresholds, and store recovery material offline.
- Stand up staging first: as Sigstore does, test every metadata change in a staging repository and run client tests against a preproduction deployment.
- Ship the initial root with the client through a trusted, out-of-band channel (the installer or OS package), never fetched on first run from the same server.
- Automate online signing and expiry monitoring: re-sign timestamp and snapshot on a schedule with alerting well before expiry; an expired timestamp stops every client from updating.
- Rehearse rotation and recovery: practise rotating an online key and a root key in staging, including the fast-forward recovery step, so a real compromise response is routine.
- Roll back safely: keep the previous updater path available behind a flag during the first releases, but plan to remove it, because a fallback that skips TUF verification is a downgrade path for attackers.
Detection and measurement
Monitor the repository and the clients. On the repository side, log every signing event and online signature, alert on any metadata change outside a signing event or CI run, and watch expiry dates. On the client side, report verification failures (bad signature, rollback, expired metadata) to telemetry, because a spike means either a repository problem or an attack on the update path.
- Expiry headroom: minimum time to expiry across all published metadata (alert when timestamp headroom falls below one day).
- Signing hygiene: percentage of root and targets signatures made with hardware keys during documented signing events (target 100%).
- Client verification failures: per thousand update checks, broken down by failure type.
- Rotation readiness: days since the last rehearsed root and online key rotation in staging.
- Coverage: share of update and download paths (application, plugins, models, configuration) verified by TUF metadata.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| MITRE ATT&CK | T1195.002 Compromise Software Supply Chain; T1072 Software Deployment Tools | Malicious updates through compromised distribution or update tools |
| MITRE CAPEC | CAPEC-187 Malicious Automated Software Update via Redirection | Redirected or spoofed update servers |
| NIST SP 800-53 Rev. 5 | SI-7 Software, Firmware, and Information Integrity; CM-14 Signed Components; SR-11 Component Authenticity; SR-4 Provenance; SC-12 Cryptographic Key Establishment and Management | Integrity verification before installation, key management for signing roles |
| NIST CSF 2.0 | PR.PS-02; GV.SC-05 | Maintaining software commensurate with risk; supply chain requirements for suppliers' update mechanisms |
Where identity fits
Every TUF role key is a non-human identity with a very specific job, and the online keys used by CI are machine credentials in cloud KMS. Restrict which workloads can call the KMS sign operation for each role, use workload identity rather than long-lived cloud keys for the CI signer, and audit every signature. See the Code Signing Security Guide.
Common failure patterns
- All roles on one key: technically TUF, practically the same single point of failure as a plain signed update.
- Root keys online: root or top-level targets keys kept in the same CI or KMS as the timestamp key, so one cloud compromise yields every role.
- Expired metadata outage: no automated re-signing or monitoring, so a missed timestamp re-sign stops every client updating.
- Trust-on-first-use root: the client downloads its initial
root.jsonfrom the repository it is meant to distrust. - Verification bypass: a legacy download path or debug flag left in the updater that skips TUF checks.
- Assuming TUF vets content: treating "signed and delivered via TUF" as "safe", with no build provenance or review of what was signed.
Practitioner checklist
- Map every path by which code, plugins, models or configuration reach clients and the credentials that can change each.
- Separate root, targets, snapshot and timestamp keys, with thresholds of at least two on root and targets.
- Keep root and top-level targets keys offline on hardware tokens held by different people.
- Use delegations so each project or publisher signs only its own paths.
- Ship the initial root metadata with the client through a trusted channel.
- Use a conformant client library and test it against a staging repository on every change.
- Automate online re-signing and alert well before any metadata expiry.
- Rehearse root and online key rotation, including fast-forward recovery.
- Report client verification failures to telemetry and investigate spikes.
- Pair TUF with build provenance so signed releases come from verified builds.
Standards and references
- TUF: The Update Framework Specification
- TUF: The Update Framework project site
- Python: PEP 458 Secure PyPI downloads with signed repository metadata
- Sigstore: root-signing
- TUF: tuf-on-ci
- TUF: python-tuf reference implementation
- MITRE ATT&CK: Compromise Software Supply Chain
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: Sigstore Guide · Software Supply Chain Security Guide · Code Signing Security Guide · Automotive Cybersecurity Guide