golang/go · error
ErrInsecurePath
ErrInsecurePath
Error message
archive/tar: insecure file path
What it means
ErrInsecurePath is returned by Reader.Next when a header's Name is non-local per filepath.IsLocal (absolute paths, parent-directory traversals like ../, drive letters on Windows, empty names) AND the GODEBUG knob tarinsecurepath is set to 0. It is a security guard against path traversal during extraction. The header is still returned alongside the error so callers who accept the risk can proceed.
Source
Thrown at src/archive/tar/common.go:38
"path"
"reflect"
"strconv"
"strings"
"time"
)
// BUG: Use of the Uid and Gid fields in Header could overflow on 32-bit
// architectures. If a large value is encountered when decoding, the result
// stored in Header will be the truncated version.
var tarinsecurepath = godebug.New("tarinsecurepath")
var (
ErrHeader = errors.New("archive/tar: invalid tar header")
ErrWriteTooLong = errors.New("archive/tar: write too long")
ErrFieldTooLong = errors.New("archive/tar: header field too long")
ErrWriteAfterClose = errors.New("archive/tar: write after close")
ErrInsecurePath = errors.New("archive/tar: insecure file path")
errMissData = errors.New("archive/tar: sparse file references non-existent data")
errUnrefData = errors.New("archive/tar: sparse file contains unreferenced data")
errWriteHole = errors.New("archive/tar: write non-NUL byte in sparse hole")
errSparseTooLong = errors.New("archive/tar: sparse map too long")
)
type headerError []string
func (he headerError) Error() string {
const prefix = "archive/tar: cannot encode header"
var ss []string
for _, s := range he {
if s != "" {
ss = append(ss, s)
}
}
if len(ss) == 0 {
return prefixView on GitHub (pinned to b6b368adc5)
Solutions
- If you trust the source, explicitly allow the header: hdr, err := tr.Next(); if err == tar.ErrInsecurePath { err = nil; /* use hdr anyway */ }.
- Sanitize names at extraction: strip leading slashes, reject '..', and join with a base dir: clean := filepath.Join(dest, filepath.Clean("/"+hdr.Name)); if !strings.HasPrefix(clean, dest) { skip }.
- Set GODEBUG=tarinsecurepath=1 to disable the guard (not recommended for untrusted input).
- Prefer the strict mode and skip offending entries rather than disabling the guard globally.
Example fix
// before
for {
hdr, err := tr.Next()
if err != nil { return err } // ErrInsecurePath aborts extraction
os.MkdirAll(filepath.Join(dest, hdr.Name), 0755)
}
// after
for {
hdr, err := tr.Next()
if err == io.EOF { break }
if err == tar.ErrInsecurePath { continue } // skip unsafe names
if err != nil { return err }
clean := filepath.Clean(filepath.Join("/", hdr.Name))
os.MkdirAll(filepath.Join(dest, clean), 0755)
} Defensive patterns
Strategy: try-catch
Validate before calling
func safeJoin(dest, name string) (string, bool) {
clean := filepath.Clean(filepath.Join("/", name))
full := filepath.Join(dest, clean)
return full, strings.HasPrefix(full+string(os.PathSeparator), dest+string(os.PathSeparator))
} Type guard
func isLocalName(name string) bool { return filepath.IsLocal(name) } Try / catch
hdr, err := tr.Next()
if errors.Is(err, tar.ErrInsecurePath) {
log.Printf("skipping non-local name %q", hdr.Name)
continue
} Prevention
- Keep GODEBUG=tarinsecurepath=0 in production for untrusted archives.
- Sanitize every extracted name with filepath.Clean and verify the result stays under dest.
- Reject absolute paths and '..' at the application layer even if the guard is off.
When it happens
Trigger: Extracting a tar whose entry Name is absolute (e.g. /etc/passwd), contains .., has a Windows drive letter (C:\x), or is otherwise rejected by filepath.IsLocal, while GODEBUG=tarinsecurepath=0 is active (the forward-compatible / strict mode).
Common situations: Extracting untrusted archives (npm packages, user uploads, scraped downloads); a tarball intentionally containing absolute paths; CI hardened with tarinsecurepath=0; transitioning code before the behavior becomes the Go default.
Related errors
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/5c8d6bf3b2caaa39.
Report an issue: GitHub.