VYPR
Moderate severityNVD Advisory· Published Mar 27, 2025· Updated Oct 14, 2025

Failure to detect delegated target rollback in tough

CVE-2025-2887

Description

During a target rollback, the client fails to detect the rollback for delegated targets. This could cause the client to fetch a target from an incorrect source, altering the target contents. Users should upgrade to tough version 0.20.0 or later and ensure any forked or derivative code is patched to incorporate the new fixes.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

In tough <0.20.0, rollback detection for delegated targets is incomplete, allowing clients to fetch tampered targets.

Vulnerability

Detail

CVE-2025-2887 affects the tough library, a Rust client for TUF repositories, in versions prior to 0.20.0. During a target rollback, the client fails to detect the rollback when delegated targets are in use [1][2]. This means that if an attacker manages to roll back a target to a previous version, the client will not recognize this as a rollback and will accept the outdated target.

Exploitation

Scenario

The vulnerability is exploitable without authentication if an attacker can intercept or manipulate the metadata updates. The client fetches snapshot metadata that lists target versions; when delegated roles are involved, the rollback detection logic misses the check for delegated targets [2][3]. An attacker positioned to perform a man-in-the-middle attack or compromise the repository could serve a rollback snapshot that the client would trust.

Impact

Successful exploitation could cause the client to fetch a target from an incorrect source, effectively altering the target contents [1]. This could lead to the installation of outdated or malicious software, depending on the context where tough is used.

Mitigation

The issue is fixed in tough version 0.20.0 [2][4]. Users should upgrade to this version or later and ensure any forked or derivative code is patched to incorporate the new fixes. The fix includes additional checks in snapshot metadata validation to ensure all roles, including delegated ones, are checked for rollback [3].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
toughcrates.io
< 0.20.00.20.0

Affected products

2

Patches

1
3345151a87c3

tough: detect rollback in snapshot metadata

https://github.com/awslabs/toughMartin HarrimanDec 11, 2024via ghsa
2 files changed · +71 0
  • tough/src/error.rs+34 0 modified
    @@ -284,6 +284,40 @@ pub enum Error {
             timestamp_old: u64,
         },
     
    +    /// The snapshot meta must contain targets.json
    +    #[snafu(display("Snapshot version {} does not contain targets.json", version))]
    +    SnapshotTargetsMetaMissing { version: u64 },
    +
    +    /// Any role in the trusted snapshot meta must also appear in the new snapshot meta
    +    #[snafu(display(
    +        "Role {} appears in snapshot version {} but not version {}",
    +        role,
    +        old_version,
    +        new_version
    +    ))]
    +    SnapshotRoleMissing {
    +        role: String,
    +        old_version: u64,
    +        new_version: u64,
    +    },
    +
    +    /// Role version in trusted snapshot must be less than or equal to version in new snapshot
    +    #[snafu(display(
    +        "Role {} version {} in snapshot {} is greater than version {} in snapshot {}",
    +        role,
    +        old_role_version,
    +        old_snapshot_version,
    +        new_role_version,
    +        new_snapshot_version
    +    ))]
    +    SnapshotRoleRollback {
    +        role: String,
    +        old_role_version: u64,
    +        old_snapshot_version: u64,
    +        new_role_version: u64,
    +        new_snapshot_version: u64,
    +    },
    +
         /// The library failed to parse a metadata file, either because it was not valid JSON or it did
         /// not conform to the expected schema.
         ///
    
  • tough/src/lib.rs+37 0 modified
    @@ -65,6 +65,7 @@ use async_recursion::async_recursion;
     pub use async_trait::async_trait;
     pub use bytes::Bytes;
     use chrono::{DateTime, Utc};
    +use error::SnapshotTargetsMetaMissingSnafu;
     use futures::StreamExt;
     use futures_core::Stream;
     use log::warn;
    @@ -1060,6 +1061,13 @@ async fn load_snapshot(
                 role: RoleType::Snapshot,
             })?;
     
    +    // 4.4 Check that snapshot.meta contains at least targets.json
    +    ensure!(
    +        snapshot.signed.meta.contains_key("targets.json"),
    +        SnapshotTargetsMetaMissingSnafu {
    +            version: snapshot.signed.version,
    +        }
    +    );
         // 3.3. Check for a rollback attack.
         //
         // 3.3.1. Note that the trusted snapshot metadata file may be checked for authenticity, but its
    @@ -1090,6 +1098,35 @@ async fn load_snapshot(
                 //   metadata file, if any, MUST continue to be listed in the new snapshot metadata
                 //   file. If any of these conditions are not met, discard the new snapshot metadata
                 //   file, abort the update cycle, and report the failure.
    +
    +            // Ensure that the trusted snapshot has at least targets.json
    +            ensure!(
    +                old_snapshot.signed.meta.contains_key("targets.json"),
    +                error::SnapshotTargetsMetaMissingSnafu {
    +                    version: old_snapshot.signed.version,
    +                }
    +            );
    +            for (name, meta) in &old_snapshot.signed.meta {
    +                ensure!(
    +                    snapshot.signed.meta.contains_key(name),
    +                    error::SnapshotRoleMissingSnafu {
    +                        role: name,
    +                        old_version: old_snapshot.signed.version,
    +                        new_version: snapshot.signed.version,
    +                    }
    +                );
    +                let new_meta = snapshot.signed.meta.get(name).unwrap();
    +                ensure!(
    +                    meta.version <= new_meta.version,
    +                    error::SnapshotRoleRollbackSnafu {
    +                        role: name,
    +                        old_role_version: meta.version,
    +                        old_snapshot_version: old_snapshot.signed.version,
    +                        new_role_version: new_meta.version,
    +                        new_snapshot_version: snapshot.signed.version,
    +                    }
    +                );
    +            }
                 if let Some(old_targets_meta) = old_snapshot.signed.meta.get("targets.json") {
                     let targets_meta =
                         snapshot
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.