argoproj/argo-workflows · error

illegal file path: %s

Error message

illegal file path: %s

What it means

During unarchiving (tar extraction), the executor joins each tar header name with the destination and verifies the result stays inside dest (classic Zip Slip protection). If a tarball entry's path escapes the destination directory (e.g. '../evil' or absolute paths), extraction aborts with 'illegal file path'.

Source

Thrown at workflow/executor/executor.go:1143

		gzr, err := file.GetGzipReader(f)
		if err != nil {
			return err
		}
		defer gzr.Close()
		tr := tar.NewReader(gzr)
		for {
			header, err := tr.Next()
			switch {
			case errors.Is(err, io.EOF):
				return nil
			case err != nil:
				return err
			case header == nil:
				continue
			}
			target := filepath.Join(dest, filepath.Clean(header.Name))
			if !strings.HasPrefix(target, filepath.Clean(dest)+string(os.PathSeparator)) {
				return fmt.Errorf("illegal file path: %s", header.Name)
			}
			switch header.Typeflag {
			case tar.TypeSymlink:
				// Validate symlink target before creating it
				linkTarget := header.Linkname
				if !filepath.IsAbs(linkTarget) {
					linkTarget = filepath.Join(filepath.Dir(target), header.Linkname)
				}
				if !strings.HasPrefix(filepath.Clean(linkTarget), filepath.Clean(dest)+string(os.PathSeparator)) {
					return fmt.Errorf("illegal symlink target: %s -> %s", header.Name, header.Linkname)
				}
				// Create parent directory if needed
				if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
					return err
				}
				err := os.Symlink(header.Linkname, target)
				if err != nil {
					return err

View on GitHub (pinned to 35bff19146)

Solutions

  1. Repackage the artifact with relative, safe member paths (tar -C dir . instead of absolute paths)
  2. Do not load artifacts from untrusted sources, or inspect the tarball (tar -tf) before use
  3. Regenerate the upstream artifact if it was built with a faulty archiving step
  4. If you control the workflow, stage the artifact and extract manually with vetting instead of relying on auto-unarchive

Example fix

# before (upstream creates tarball with traversal)
tar cf out.tar /work/../etc/passwd
# after
tar -C /work -cf out.tar .
Defensive patterns

Strategy: try-catch

Validate before calling

// Inspect a tarball for traversal entries before uploading it as an artifact:
// tar -tf artifact.tar | grep -E '(^/|\.\./)' && echo "unsafe paths found"

Try / catch

if err := loadArtifacts(ctx); err != nil {
	if strings.Contains(err.Error(), "illegal file path") {
		// reject the artifact: it contains Zip-Slip paths; repackage upstream
	}
}

Prevention

When it happens

Trigger: Extracting a (possibly malicious or malformed) tar artifact whose member names contain path traversal sequences ('..'), absolute paths, or symlink-crafted names that resolve outside the destination after filepath.Join+Clean.

Common situations: Untrusted third-party artifact (http artifact or someone else's output) containing a Zip-Slip payload; a build script that tarred absolute paths; corrupted/renamed entries where '..' slipped into the header name.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/c5663dd9180662b8. Report an issue: GitHub.