gitbutlerapp/gitbutler · critical · anyhow::Error

Signature verification failed - the download may have been t

Error message

Signature verification failed - the download may have been tampered with: {e}

What it means

The installer verifies the downloaded artifact against a pinned minisign public key (`RWTrOEI+im1XYA9RBwyxnzFN/evFzJhU1lbQ70LVayWH3WRo7xQnRLD2`) by streaming the file through the verifier in 64 KB chunks. `verifier.finalize()` failing means the streamed bytes do not match the signature — a corrupted or truncated download, a mismatched artifact/signature pair, or genuinely modified content.

Source

Thrown at crates/but-installer/src/install.rs:88

    let mut file =
        File::open(installable).context("Failed to open installable for verification")?;
    let mut verifier = public_key
        .verify_stream(&signature)
        .map_err(|e| anyhow!("Failed to initialize signature verifier: {e}"))?;

    // Read and verify file in 64KB chunks
    let mut buffer = [0u8; 65536];
    loop {
        let bytes_read = file.read(&mut buffer)?;
        if bytes_read == 0 {
            break;
        }
        verifier.update(&buffer[..bytes_read]);
    }

    // Finalize verification
    verifier.finalize().map_err(|e| {
        anyhow!("Signature verification failed - the download may have been tampered with: {e}")
    })?;

    ui::info("Signature verification passed");
    Ok(())
}

#[cfg(test)]
mod tests {
    use std::io::Write;

    use super::*;

    #[test]
    fn test_verify_signature_empty() {
        let temp_dir = tempfile::tempdir().unwrap();
        let test_file = temp_dir.path().join("test.tar.gz");

        // Create a dummy file

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Delete the artifact and signature, re-download both from the official release, and retry.
  2. Check the artifact's size and checksum against the release manifest to catch truncation.
  3. Ensure artifact and signature come from the same release version — no version skew between the two downloads.
  4. If the project rotated its signing key, move to a current installer build whose pinned key matches.
  5. Rule out proxies/AV rewriting downloads; fetch over a clean network path.

Example fix

// before
verify_signature(&artifact, &sig_b64, &tmp)?;
install(&artifact)?;

// after
if let Err(e) = verify_signature(&artifact, &sig_b64, &tmp) {
    if e.to_string().contains("Signature verification failed") {
        std::fs::remove_file(&artifact)?; // discard untrusted bytes
        re_download(&release).await?;     // fresh artifact + signature pair
    }
}
verify_signature(&artifact, &sig_b64, &tmp)?;
install(&artifact)?;
Defensive patterns

Strategy: try-catch

Validate before calling

use std::fs;

// Cheap pre-checks before minisign verification
let sig = fs::read_to_string(&sig_path)?;
let len = fs::metadata(&artifact)?.len();
if sig.trim().is_empty() || len == 0 {
    anyhow::bail!("Incomplete download - refetch artifact and signature");
}

Try / catch

match verify_signature(&artifact, &signature_b64, &tmp_dir) {
    Ok(()) => {}
    Err(e) if e.to_string().contains("Signature verification failed") => {
        // Security-sensitive: do NOT install. Remove the artifact and alert.
        let _ = std::fs::remove_file(&artifact);
        anyhow::bail!("Install aborted, possible tampering: {e}");
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: `verify_signature` runs after a download whose bytes don't match the minisignature: an interrupted HTTP transfer saved to disk, a signature taken from a different release than the artifact, a body rewritten by a TLS-inspecting proxy or antivirus, or a pinned key that no longer matches the project's current signing key.

Common situations: Flaky networks truncating downloads; mirrors or caches pairing artifacts with stale signatures; corporate proxies with TLS inspection rewriting bodies; signing-key rotations leaving old installers with the previous pinned key; locally rebuilt artifacts shipped with the official signature.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/1bd2776d58f52600. Report an issue: GitHub.