Skip to content

proposal: archive/tar, archive/zip: add NewReaderOptions with directory traversal defenses #57850

Description

@neild

This is another attempt at hardening the archive/tar and archive/zip packages against file traversal attacks, fixing #25849.

Naive handling of archives containing filenames such as ../../../etc/passwd leads to security vulnerabilities. (See #55356 for a bunch of reference CVEs.) In #55356, I proposed changing archive/tar and archive/zip to return an ErrInsecurePath error when encountering an unsafe filename. Unfortunately, we subsequently discovered that Docker images frequently include filenames with absolute paths, making this change infeasible.

I propose adding new safe-by-default functions to archive/tar and archive/zip.

package tar

type ReaderOptions struct {
	AllowAbsolutePaths          bool
	AllowRelativePathComponents bool
}

// NewReaderWithOptions creates a new reader reading from r.
//
// The Reader's Next method will return ErrInsecurePath and a valid
// *Header if the next file's name is:
//
//   - absolute and opts.AllowAbsolutePaths is not set;
//   - contains a ".." path component and opts.AllowRelativePathComponents is not set; or
//   - on Windows, a reserved file name such as "NUL".
func NewReaderWithOptions(r io.Reader, opts ReaderOptions) *Reader
package zip

type ReaderOptions struct {
	AllowAbsolutePaths          bool
	AllowRelativePathComponents bool
}

// NewReaderWithOptions returns a new Reader reading from r,
// which is assumed to have the given size in bytes.
//
// 
// NewReaderWithOptions will return ErrInsecurePath and a valid
// *Reader if the archive contains file names that are:
//
//   - absolute and opts.AllowAbsolutePaths is not set;
//   - contains a ".." path component and opts.AllowRelativePathComponents is not set;
//   - contain a backslash (\) character; or
//   - on Windows, a reserved file name such as "NUL".
func NewReaderWithOptions(r io.ReaderAt, size int64, opts ReaderOptions) (*Reader, error)

The NewReaderWithOptions functions will provide the same functionality as proposed in #55356, but in a new API to avoid breaking existing users. In addition, these functions provide an easy way for users who want to accept some forms of unsafe path to do so while still defending against unexpected cases: For example, permitting absolute filenames while rejecting ones containing unexpected backslash characters.

I further propose that we update the NewReader documentation to encourage all users to migrate to NewReaderWithOptions. Once all supported Go versions include NewReaderWithOptions, we can go further and deprecate NewReader. We might also consider changing NewReader to be safe by default at some point, although that decision is out of scope for this proposal.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status
    Hold

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions