helm/helm · error
path contains '..', which is illegal
Error message
path contains '..', which is illegal
What it means
Thrown by cleanJoin (internal/plugin/installer/extractor.go:106) when a tar member name, after backslashes are normalized to '/', contains '..' as a path segment. Parent-directory traversal is the classic tar-slip attack, and Helm's policy is to reject (not clean) any path that looks like an escape attempt from the extraction directory.
Source
Thrown at internal/plugin/installer/extractor.go:106
// - The path component `..` is considered suspicious, and therefore illegal
// - The character \ (backslash) is treated as a path separator and is converted to /.
// - Beginning a path with a path separator is illegal
// - Rudimentary symlink protections are offered by SecureJoin.
func cleanJoin(root, dest string) (string, error) {
// On Windows, this is a drive separator. On UNIX-like, this is the path list separator.
// In neither case do we want to trust a TAR that contains these.
if strings.Contains(dest, ":") {
return "", errors.New("path contains ':', which is illegal")
}
// The Go tar library does not convert separators for us.
// We assume here, as we do elsewhere, that `\\` means a Windows path.
dest = strings.ReplaceAll(dest, "\\", "/")
// We want to alert the user that something bad was attempted. Cleaning it
// is not a good practice.
if slices.Contains(strings.Split(dest, "/"), "..") {
return "", errors.New("path contains '..', which is illegal")
}
// If a path is absolute, the creator of the TAR is doing something shady.
if path.IsAbs(dest) {
return "", errors.New("path is absolute, which is illegal")
}
// SecureJoin will do some cleaning, as well as some rudimentary checking of symlinks.
// The directory needs to be cleaned prior to passing to SecureJoin or the location may end up
// being wrong or returning an error. This was introduced in v0.4.0.
root = filepath.Clean(root)
newpath, err := securejoin.SecureJoin(root, dest)
if err != nil {
return "", err
}
return filepath.ToSlash(newpath), nil
}View on GitHub (pinned to 2a29f1770b)
Solutions
- Repack from inside the plugin directory so member names never traverse upward: 'cd myplugin && tar -czf ../myplugin-1.0.0.tgz .'
- Inspect entries first with 'tar -tzf file.tgz' and remove/relocate any entry containing '..' segments
- If the archive came from a third party, do not attempt to bypass the check - the tarball is presumed malicious; obtain a clean artifact
Example fix
// before: entry '../../../plugin.yaml' or 'myplugin/../../x' in the archive tar -tzf bad.tgz # shows ../.. entries // after: rebuild with only downward-relative paths cd myplugin && tar -czf ../myplugin-1.0.0.tgz .
Defensive patterns
Strategy: validation
Validate before calling
func tarHasTraversal(path string) (bool, error) {
f, err := os.Open(path)
if err != nil {
return false, err
}
defer f.Close()
gz, err := gzip.NewReader(f)
if err != nil {
return false, err
}
tr := tar.NewReader(gz)
for {
h, err := tr.Next()
if err == io.EOF {
return false, nil
}
if err != nil {
return false, err
}
norm := strings.ReplaceAll(h.Name, "\\", "/")
if slices.Contains(strings.Split(norm, "/"), "..") {
return true, nil
}
}
} Try / catch
if err := installer.Install(i); err != nil {
if strings.Contains(err.Error(), "path contains '..'") {
// tar-slip attempt or bad packaging: reject the artifact entirely
return err
}
return err
} Prevention
- Never build archives by walking above the packaging root
- Add a CI lint step that scans 'tar -tzf' output for '..' segments
- Treat any archive that fails these checks as malicious, not as a packaging nuisance to auto-fix
When it happens
Trigger: Installing a plugin archive (HTTP tarball via TarGzExtractor.Extract, local tarball, or OCI extractTar) whose member name contains a '..' segment, e.g. '../../etc/passwd' or 'pkg/../../escape'. A single header triggers the error and aborts the entire install.
Common situations: Hand-packed tarballs that include relative parent references; archives produced by tools that preserve '../../' fragments; malicious third-party plugin archives. Occasionally a repackaging script that walks above its root dir creates such entries accidentally.
Related errors
- path contains ':', which is illegal
- path is absolute, which is illegal
- failed to extract archive: %w
- chart illegally contains content outside the base directory:
- chart illegally contains absolute paths
AI-assisted analysis of helm/helm@2a29f1770b (2026-08-15).
Data as JSON: /api/errors/f89adcbf0b66c378.
Report an issue: GitHub.