argoproj/argo-workflows · error
%s: Illegal file path
Error message
%s: Illegal file path
What it means
Thrown by the executor while extracting a zip archive (artifact unpack): a zip entry's joined destination path does not stay under the extraction directory. This is a Zip-Slip (path traversal) guard — an entry name like `../../etc/passwd` would otherwise escape `dest` and write outside it. The executor intentionally rejects such archives instead of following the malicious path.
Source
Thrown at workflow/executor/executor.go:1245
panic(err)
}
}()
// Closure to address file descriptors issue with all the deferred .Close() methods
extractAndWriteFile := func(f *zip.File) error {
rc, err := f.Open()
if err != nil {
return err
}
defer func() {
if closeErr := rc.Close(); closeErr != nil {
panic(closeErr)
}
}()
path := filepath.Join(dest, f.Name)
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("%s: Illegal file path", path)
}
if f.FileInfo().IsDir() {
if err = os.MkdirAll(path, f.Mode()); err != nil {
return err
}
} else {
if err = os.MkdirAll(filepath.Dir(path), f.Mode()); err != nil {
return err
}
outFile, openErr := os.OpenFile(filepath.Clean(path), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if openErr != nil {
return openErr
}
defer func() {
if closeErr := outFile.Close(); closeErr != nil {
panic(closeErr)
}View on GitHub (pinned to 35bff19146)
Solutions
- Inspect the zip with `unzip -l` and remove/rename entries containing `..` or leading absolute paths
- Rebuild the artifact with relative entry paths (e.g. `zip -r artifact.zip ./dir` from the archive root, not `zip artifact.zip /abs/paths`)
- Verify the artifact source — the archive likely comes from an untrusted or compromised producer
- If you control extraction, extract into a directory whose prefix the entries genuinely belong under
Example fix
// before: packer used absolute path
zip.Add("/etc/hosts", data) // entry name "/etc/hosts"
// after: use paths relative to the archive root
zip.Add("etc/hosts", data) Defensive patterns
Strategy: validation
Validate before calling
cleanDest := filepath.Clean(dest)
for _, f := range zipReader.File {
path := filepath.Join(dest, f.Name)
if !strings.HasPrefix(path, cleanDest+string(os.PathSeparator)) {
return fmt.Errorf("unsafe zip entry: %s", f.Name)
}
} Type guard
func isSafeZipEntry(dest, name string) bool {
return strings.HasPrefix(filepath.Join(dest, name), filepath.Clean(dest)+string(os.PathSeparator))
} Prevention
- Build archives with relative paths from the archive root (zip -r from inside the directory)
- Scan artifacts with `unzip -l` for `..` or absolute entry names before publishing
- Never unzip untrusted artifacts into shared/host paths
When it happens
Trigger: Unpacking a zip artifact whose central directory contains an entry with a name using `..` segments or an absolute path, so that filepath.Join(dest, f.Name) does not have filepath.Clean(dest)+os.PathSeparator as prefix.
Common situations: Artifact was produced by a malicious/buggy packer that injects traversal entry names; archives created on Windows or with absolute paths like `/abs/file`; hand-crafted zip files submitted via git/http/raw artifacts; upgrading to a version that hardened against CVE-class zip-slip and previously-'working' malicious archives now fail.
Related errors
- illegal file path: %s
- artifact key %q must not contain '..'
- illegal symlink target: %s -> %s
- illegal file path after symlink resolution: %s resolves outs
- artifact key %q must start with %q
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/030ef8a7e17207f1.
Report an issue: GitHub.