BoundaryML/baml · critical · FetchError
archive contains unsafe path
Error message
archive contains unsafe path {path} What it means
FetchError::UnsafeArchivePath is thrown by baml_release when an entry inside the downloaded zip archive has an unsafe path (e.g. absolute paths, `..` traversal components, or paths escaping the extraction directory). This is a zip-slip protection: extracting such entries could write files outside the intended install directory.
Solutions
- Do not attempt to bypass this check — it indicates a dangerous archive
- Verify the artifact's checksum against the official manifest; if it also fails, the download is tampered
- If you control packaging, fix the packager to emit plain relative entry names
- Report the artifact immediately as potentially compromised
Example fix
// before (naive extraction, zip-slip risk)
for f in zip.entries() { f.extract(&dest)?; }
// after (library already rejects; reject at your layer too)
for f in zip.entries() {
let name = f.name();
if name.contains("..") || Path::new(name).is_absolute() {
bail!("unsafe archive path {name}");
}
f.extract(&dest)?;
} Defensive patterns
Strategy: validation
Validate before calling
fn archive_entries_safe(names: &[&str]) -> bool {
names.iter().all(|n| {
let p = std::path::Path::new(n);
!p.is_absolute() && !n.split('/').any(|c| c == "..")
})
} Type guard
fn is_unsafe_path(e: &FetchError) -> bool {
matches!(e, FetchError::UnsafeArchivePath { .. })
} Try / catch
match install(v) {
Err(FetchError::UnsafeArchivePath { path }) => {
error!("archive contains unsafe path {path}; refusing install — possible tampering");
std::process::exit(1);
}
other => other,
} Prevention
- Never disable zip-slip/path checks in the extractor
- Verify checksums before extraction so tampering is caught earlier
- Reject archives with absolute or `..` entry names at ingestion
- Treat this error as a security signal, not a transient failure
When it happens
Trigger: Extracting a release archive that contains an entry name like `/etc/passwd`, `../../.bashrc`, or a Windows drive path — the extractor refuses before writing anything.
Common situations: A tampered or malicious artifact (which checksum validation should also catch), hand-crafted archives used with local manifest overrides in testing, or a packaging bug generating entry names with parent components.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- artifact URL must use HTTPS
- Checksum mismatch: expected
- CSRF state mismatch
- ErrChecksumMismatch
- profiling store contains a symlink
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/844a484b783cba11.
Report an issue: GitHub.
Appendix: source
Thrown at baml_language/crates/baml_release/src/lib.rs:99
HttpStatus {
url: String,
status: reqwest::StatusCode,
},
#[error("manifest 404 for version {version} (not released yet?)")]
ManifestNotFound { version: String },
#[error("manifest schema {got} not supported (max {max}); run `baml self-update`")]
ManifestSchemaTooNew { got: u32, max: u32 },
#[error("target {target} not built for version {version}")]
TargetNotInManifest { target: String, version: String },
#[error("sha256 mismatch for {url}: expected {expected}, got {got}")]
ChecksumMismatch {
url: String,
expected: String,
got: String,
},
#[error("archive missing expected binary {name}")]
BinaryNotInArchive { name: String },
#[error("archive contains unsafe path {path}")]
UnsafeArchivePath { path: String },
#[error("disk error: {0}")]
Io(#[from] std::io::Error),
#[error("zip archive error: {0}")]
Zip(#[from] zip::result::ZipError),
}
#[derive(Debug, Clone)]
pub struct Fetcher {
pub spec: ReleaseSpec,
pub product: Product,
pub manifest_base_url: String,
pub release_repo: String,
artifact: Option<Artifact>,
}
impl Fetcher {
pub fn default_for(spec: ReleaseSpec, product: Product) -> Self {View on GitHub (pinned to bd85ce9dee)