fix(cli): validate IDs on backup restore (audit B4)

Crafted .relbak files with IDs like "../../.bashrc" could escape the
target directory. Now validates that item/attachment IDs are hex-only
via is_valid() before any fs::write.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-05-02 02:21:49 -04:00
parent 2739eb4194
commit 81f1f8ec31

View File

@@ -1586,6 +1586,7 @@ fn tar_directory(dir: &std::path::Path) -> Result<Vec<u8>> {
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)?;