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

  1. Reject/quarantine the archive — it likely contains a path-traversal (Zip-Slip) entry
  2. Rebuild the archive so entries are relative paths under a single root directory
  3. Sanitize entries on the producing side (strip leading '/' and '..' components)
  4. 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

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


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/8614b6386da392c4. Report an issue: GitHub.