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.
This is another attempt at hardening the
archive/tarandarchive/zippackages against file traversal attacks, fixing #25849.Naive handling of archives containing filenames such as
../../../etc/passwdleads to security vulnerabilities. (See #55356 for a bunch of reference CVEs.) In #55356, I proposed changingarchive/tarandarchive/zipto return anErrInsecurePatherror 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/tarandarchive/zip.The
NewReaderWithOptionsfunctions 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
NewReaderdocumentation to encourage all users to migrate toNewReaderWithOptions. Once all supported Go versions includeNewReaderWithOptions, we can go further and deprecateNewReader. We might also consider changingNewReaderto be safe by default at some point, although that decision is out of scope for this proposal.