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 fileView on GitHub (pinned to caf1f223d3)
Solutions
- Delete the artifact and signature, re-download both from the official release, and retry.
- Check the artifact's size and checksum against the release manifest to catch truncation.
- Ensure artifact and signature come from the same release version — no version skew between the two downloads.
- If the project rotated its signing key, move to a current installer build whose pinned key matches.
- 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
- Download artifact and signature together from the same official release; never mix versions.
- Check size/SHA-256 before signature verification to catch truncated downloads cheaply.
- Treat verification failure as tamper-suspected: quarantine and alert — never fall back to installing unverified bytes.
- Track the project's signing-key rotations; a stale pinned key causes false 'tampered' failures on legitimate artifacts.
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
- Signature is empty - refusing to verify without a valid sign
- BUG: Sensitive data cannot be serialized - it needs to be ex
- Too many arguments. Usage: but-installer [version|nightly] o
- unsupported OS or architecture: {os} {arch}
- Download of {url} failed with HTTP status: {response_code}
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/1bd2776d58f52600.
Report an issue: GitHub.