Billionmail/BillionMail · critical
illegal file path:
Error message
illegal file path:
What it means
During gzip decompression, decompressHelper resolves each tar entry's filename to an absolute path and verifies it stays under the destination root. If the archive entry escapes the target path (e.g. via '../' path traversal), the unpacker refuses it to prevent a Zip-Slip attack. The offending entry name is appended to the message.
Source
Thrown at core/internal/service/compress/gzip.go:151
// remove ../ from filename
arcName := filepath.ToSlash(filepath.Clean(header.Name))
if strings.Contains(arcName, "../") {
arcName = strings.Replace(arcName, "../", "", -1)
}
filename := filepath.Join(dst, arcName)
// get absolute path of the file
filenameAbs, err := filepath.Abs(filename)
if err != nil {
return err
}
// check if the file is under the decompression target path
if !strings.HasPrefix(filenameAbs, dstAbs) {
return errors.New("illegal file path: " + filename)
}
// check if it's a directory
// if it's a directory, create it and skip
if header.FileInfo().IsDir() {
err = os.MkdirAll(filename, 0755)
if err != nil {
return err
}
continue
}
// create directory
err = os.MkdirAll(filepath.Dir(filename), 0755)
if err != nil {View on GitHub (pinned to fc36c76c05)
Solutions
- Reject/quarantine the archive — it likely contains a path-traversal (Zip-Slip) entry
- Rebuild the archive so entries are relative paths under a single root directory
- Sanitize entries on the producing side (strip leading '/' and '..' components)
- If trusted and intentional, extract with a lower-level tool that permits those paths — at your own risk
Example fix
// before (producer)
hdr.Name = "/etc/passwd"
// after
hdr.Name = filepath.Join("root", "/etc/passwd") // relative, stays under extraction dir Defensive patterns
Strategy: validation
Validate before calling
ok, err := func() (bool, error) {
r, err := os.Open(archivePath); if err != nil { return false, err }
defer r.Close()
gz, _ := gzip.NewReader(r)
tr := tar.NewReader(gz)
dstAbs, _ := filepath.Abs(dst)
for {
h, err := tr.Next(); if err == io.EOF { return true, nil }; if err != nil { return false, err }
abs, _ := filepath.Abs(filepath.Join(dst, h.Name))
if !strings.HasPrefix(abs, dstAbs+string(os.PathSeparator)) { return false, fmt.Errorf("unsafe entry: %s", h.Name) }
}
}()
_ = ok Try / catch
if err := u.Decompress(dst, src); err != nil && strings.HasPrefix(err.Error(), "illegal file path") {
// quarantine archive, log offending entry from err message, do not retry
} Prevention
- Treat all third-party archives as untrusted; never bypass the traversal check
- Scan archive entries (names only) before extraction in a sandbox
- Generate archives with relative, cleaned paths only
- Keep the extraction root dedicated and least-privilege
When it happens
Trigger: Calling GzipUnpacker.Decompress on a .tar.gz whose entries contain absolute paths or '../' sequences that resolve outside dst; typically archives crafted by attackers or produced on other directory layouts.
Common situations: Processing untrusted user-uploaded archives; legacy archives with absolute paths; tooling that builds tar entries without filepath.Join on the base dir.
Related errors
- illegal file path:
- disk quota exceeded
- unexpected signing method: %v
- disk quota exceeded
- rar command not found, please install it first
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/8614b6386da392c4.
Report an issue: GitHub.