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

Improper timestamp caching during snapshot rollback in tough

CVE-2025-2888

Description

During a snapshot rollback, the client incorrectly caches the timestamp metadata. If the client checks the cache when attempting to perform the next update, the update timestamp validation will fail, preventing the next update until the cache is cleared. 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.

A snapshot rollback in tough versions before 0.20.0 causes the client to incorrectly cache rejected timestamp metadata, blocking future updates until the cache is cleared.

Root

Cause

CVE-2025-2888 is an issue in the tough Rust client library for TUF repositories where, during a snapshot rollback, the client incorrectly caches the timestamp metadata even after correctly rejecting the rollback [1][2]. According to the advisory and commit details, the library failed to properly invalidate or clear the cached timestamp when a rollback was detected, meaning the stale metadata persisted in the cache [3].

Exploitation

Preconditions

The vulnerability triggers during a normal snapshot rollback scenario. An attacker capable of performing a rollback attack could supply an older, validly-signed timestamp metadata file. The client correctly rejects the rollback but then caches the rejected metadata. When the client subsequently checks this cache on the next update cycle, the timestamp version validation fails because the cached version is now considered older than the trusted version, preventing the client from consuming any valid updates [1][2]. No additional authentication or network position is required beyond what is typical for a TUF client; the flaw exists entirely in the client-side cache logic.

Impact

An attacker can exploit this to effectively freeze a client by denying it the ability to process any future updates. This denial of service (DoS) prevents the client from applying security patches or other critical updates, leaving the system in a known, potentially vulnerable state until the cache is manually cleared [1][2][4]. The issue does not allow arbitrary code execution or direct data compromise, but it undermines the primary security guarantee of a secure update system.

Mitigation

AWS and the tough maintainers have released a fix in version 0.20.0 [2][4]. The commit at [3] adds explicit checks for rollback detection in the timestamp metadata, including validation that the timestamp meta contains exactly one entry (snapshot.json) and proper version comparison before caching. Users must upgrade to tough >=0.20.0 and ensure any forked or derivative code incorporates the same fixes [1][2][4].

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

3

Patches

1
9b400e1c8b7d

tough: detect rollback in timestamp metafiles

https://github.com/awslabs/toughMartin HarrimanDec 11, 2024via ghsa
2 files changed · +71 2
  • tough/src/error.rs+28 0 modified
    @@ -256,6 +256,34 @@ pub enum Error {
             backtrace: Backtrace,
         },
     
    +    /// A timestamp metadata file must contain exactly one entry
    +    #[snafu(display(
    +        "Timestamp version {} meta length {} is not exactly one",
    +        version,
    +        meta_length
    +    ))]
    +    TimestampMetaLength { version: u64, meta_length: usize },
    +
    +    /// A timestamp metadata file must contain a meta entry for snapshot.json
    +    #[snafu(display("No snapshot meta in timestamp.json version {}", version))]
    +    MissingSnapshotMeta { version: u64 },
    +
    +    /// The snapshot version in a newer timestamp metadata file must be greater than
    +    /// or equal to the version in an older timestamp.
    +    #[snafu(display(
    +        "Snapshot version {} in timestamp {} is less than {} in timestamp {}",
    +        snapshot_new,
    +        timestamp_new,
    +        snapshot_old,
    +        timestamp_old
    +    ))]
    +    OlderSnapshotInTimestamp {
    +        snapshot_new: u64,
    +        timestamp_new: u64,
    +        snapshot_old: u64,
    +        timestamp_old: 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+43 2 modified
    @@ -883,7 +883,7 @@ async fn load_timestamp(
                 role: RoleType::Timestamp,
             })?;
     
    -    // 2.1. Check signatures. The new timestamp metadata file must have been signed by a threshold
    +    // 5.4.2. Check signatures. The new timestamp metadata file must have been signed by a threshold
         //   of keys specified in the trusted root metadata file. If the new timestamp metadata file is
         //   not properly signed, discard it, abort the update cycle, and report the signature failure.
         root.signed
    @@ -892,7 +892,22 @@ async fn load_timestamp(
                 role: RoleType::Timestamp,
             })?;
     
    -    // 2.2. Check for a rollback attack. The version number of the trusted timestamp metadata file,
    +    // 4.6. The meta component must contain exactly one entry, snapshot.json
    +    ensure!(
    +        timestamp.signed.meta.len() == 1,
    +        error::TimestampMetaLengthSnafu {
    +            version: timestamp.signed.version,
    +            meta_length: timestamp.signed.meta.len(),
    +        }
    +    );
    +    let snapshot_meta = timestamp.signed.meta.get("snapshot.json");
    +    ensure!(
    +        snapshot_meta.is_some(),
    +        error::MissingSnapshotMetaSnafu {
    +            version: timestamp.signed.version,
    +        }
    +    );
    +    // 5.4.3.1. Check for a rollback attack. The version number of the trusted timestamp metadata file,
         //   if any, must be less than or equal to the version number of the new timestamp metadata
         //   file. If the new timestamp metadata file is older than the trusted timestamp metadata
         //   file, discard it, abort the update cycle, and report the potential rollback attack.
    @@ -910,6 +925,32 @@ async fn load_timestamp(
                         new_version: timestamp.signed.version
                     }
                 );
    +            // 4.6 trusted timestamp meta must have one entry, snapshot.json
    +            ensure!(
    +                old_timestamp.signed.meta.len() == 1,
    +                error::TimestampMetaLengthSnafu {
    +                    version: old_timestamp.signed.version,
    +                    meta_length: old_timestamp.signed.meta.len(),
    +                }
    +            );
    +            let old_snapshot_meta = old_timestamp.signed.meta.get("snapshot.json");
    +            ensure!(
    +                old_snapshot_meta.is_some(),
    +                error::MissingSnapshotMetaSnafu {
    +                    version: old_timestamp.signed.version,
    +                }
    +            );
    +            // 5.4.3.2 trusted snapshot version less than or equal to new snapshot version
    +            // (rollback attack to fetch older snapshot object)
    +            ensure!(
    +                old_snapshot_meta.unwrap().version <= snapshot_meta.unwrap().version,
    +                error::OlderSnapshotInTimestampSnafu {
    +                    snapshot_new: snapshot_meta.unwrap().version,
    +                    timestamp_new: timestamp.signed.version,
    +                    snapshot_old: old_snapshot_meta.unwrap().version,
    +                    timestamp_old: old_timestamp.signed.version,
    +                }
    +            );
             }
         }
     
    

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.