diff --git a/crates/relicario-cli/src/main.rs b/crates/relicario-cli/src/main.rs index 84d7e21..b450c54 100644 --- a/crates/relicario-cli/src/main.rs +++ b/crates/relicario-cli/src/main.rs @@ -1586,6 +1586,7 @@ fn tar_directory(dir: &std::path::Path) -> Result> { fn cmd_backup_restore(input: PathBuf, target: PathBuf) -> Result<()> { use std::fs; use relicario_core::backup; + use relicario_core::{ItemId, AttachmentId}; use zeroize::Zeroizing; let target = if target.is_absolute() { @@ -1634,9 +1635,18 @@ fn cmd_backup_restore(input: PathBuf, target: PathBuf) -> Result<()> { fs::write(target.join("settings.enc"), &unpacked.settings_enc)?; for item in &unpacked.items { + let item_id = ItemId(item.id.clone()); + if !item_id.is_valid() { + anyhow::bail!("invalid item ID in backup: {} (path traversal blocked)", item.id); + } fs::write(target.join("items").join(format!("{}.enc", item.id)), &item.ciphertext)?; } for a in &unpacked.attachments { + let item_id = ItemId(a.item_id.clone()); + let att_id = AttachmentId(a.attachment_id.clone()); + if !item_id.is_valid() || !att_id.is_valid() { + anyhow::bail!("invalid attachment ID in backup (path traversal blocked)"); + } let dir = target.join("attachments").join(&a.item_id); fs::create_dir_all(&dir)?; fs::write(dir.join(format!("{}.enc", a.attachment_id)), &a.ciphertext)?;