Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: zip slip issue #19711

Closed

Conversation

McGon-Fid
Copy link

fixes: #19710

a496278_fidelity commented on Jul 23
codeql issue:
rule - go/zipslip
severity - error
level - high

Summary: Arbitrary file access during archive extraction ("Zip Slip")

Unsanitized archive entry, which may contain '..', is used in a file system operation.
Unsanitized archive entry, which may contain '..', is used in a file system operation.
Unsanitized archive entry, which may contain '..', is used in a file system operation.

Fix added to lines 74-94 in util/io/files/tar.go

@McGon-Fid McGon-Fid requested a review from a team as a code owner August 28, 2024 12:36
Copy link

bunnyshell bot commented Aug 28, 2024

❌ Preview Environment deleted from Bunnyshell

Available commands (reply to this comment):

  • 🚀 /bns:deploy to deploy the environment

Copy link

bunnyshell bot commented Aug 28, 2024

❌ Preview Environment deleted from Bunnyshell

Available commands (reply to this comment):

  • 🚀 /bns:deploy to deploy the environment

Copy link
Member

@nitishfy nitishfy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lint is failing, can you please fix it?

@McGon-Fid McGon-Fid changed the title Fix for zip slip issue in util/io/files/tar.go Fix for zip slip issue Sep 4, 2024
@McGon-Fid McGon-Fid changed the title Fix for zip slip issue fix for zip slip issue Sep 4, 2024
@McGon-Fid McGon-Fid changed the title fix for zip slip issue fix: zip slip issue Sep 4, 2024
@McGon-Fid
Copy link
Author

Linting errors addressed @nitishfy Thanks

// Sanity check to protect against zip-slip

normalizedHeaderName := filepath.Clean(header.Name)
if normalizedHeaderName == "." || strings.Contains(normalizedHeaderName, "..") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if normalizedHeaderName == "." || strings.Contains(normalizedHeaderName, "..") {
if normalizedHeaderName == "." || strings.Contains(normalizedHeaderName, "..") {

you need to import the strings package in order to use the method.

Copy link
Member

@nitishfy nitishfy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lint and e2e tests are failing. These are the logs i found from the details

Error: util/io/files/tar.go:87:37: undefined: strings (typecheck)
  package files
  Error: util/tgzstream/stream.go:13:2: could not import github.com/argoproj/argo-cd/v2/util/io/files (-: # github.com/argoproj/argo-cd/v2/util/io/files
  Error: util/io/files/tar.go:87:37: undefined: strings) (typecheck)
  	"github.com/argoproj/argo-cd/v2/util/io/files"
  	^
  Error: util/cmp/stream.go:20:2: could not import github.com/argoproj/argo-cd/v2/util/io/files (-: # github.com/argoproj/argo-cd/v2/util/io/files
  Error: util/io/files/tar.go:87:37: undefined: strings) (typecheck)
  	"github.com/argoproj/argo-cd/v2/util/io/files"
  	^
  Error: util/manifeststream/stream.go:17:2: could not import github.com/argoproj/argo-cd/v2/util/io/files (-: # github.com/argoproj/argo-cd/v2/util/io/files
  Error: util/io/files/tar.go:87:37: undefined: strings) (typecheck)
  	"github.com/argoproj/argo-cd/v2/util/io/files"
  	^
  Error: test/e2e/fixture/certs/certs.go:21:43: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  		errors.FailOnErr(fixture.RunCli(args...))
  		                                        ^
  Error: test/e2e/fixture/certs/certs.go:23:43: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  		errors.FailOnErr(fixture.RunCli(args...))
  		                                        ^
  Error: test/e2e/fixture/certs/certs.go:32:43: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  		errors.FailOnErr(fixture.RunCli(args...))
  		                                        ^
  Error: test/e2e/fixture/certs/certs.go:49:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/gpgkeys/gpgkeys.go:17:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/gpgkeys/gpgkeys.go:31:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:[34](https://github.com/argoproj/argo-cd/actions/runs/10596799409/job/29365577197?pr=19711#step:4:36):42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:47:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:64:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:79:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:91:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:98:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:116:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:1[35](https://github.com/argoproj/argo-cd/actions/runs/10596799409/job/29365577197?pr=19711#step:4:37):42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:144:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:153:42: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.RunCli(args...))
  	                                        ^
  Error: test/e2e/fixture/repos/repos.go:167:79: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.Run("", "helm", "dependency", "build", chartAbsPath))
  	                                                                             ^
  Error: test/e2e/fixture/repos/repos.go:168:94: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	errors.FailOnErr(fixture.Run("", "helm", "package", chartAbsPath, "--destination", tempDest))
  	                                                                                            ^
  Error: test/e2e/fixture/repos/repos.go:176:3: not enough arguments in call to errors.FailOnErr
  	have (unknown type)
  	want (interface{}, error) (typecheck)
  	))
  	 ^
  Error: test/e2e/fixture/app/actions.go:110:52: undefined: Application (typecheck)
  func (a *Actions) CreateFromFile(handler func(app *Application), flags ...string) *Actions {
                                                     ^
  Error: test/e2e/fixture/app/actions.go:[39](https://github.com/argoproj/argo-cd/actions/runs/10596799409/job/29365577197?pr=19711#step:4:41)1:39: undefined: RefreshType (typecheck)
  func (a *Actions) Refresh(refreshType RefreshType) *Actions {
                                        ^
  Error: test/e2e/fixture/app/consequences.go:45:44: undefined: Application (typecheck)
  func (c *Consequences) And(block func(app *Application)) *Consequences {

Updating PR
Copy link

codecov bot commented Sep 9, 2024

Codecov Report

Attention: Patch coverage is 80.00000% with 1 line in your changes missing coverage. Please review.

Project coverage is 55.81%. Comparing base (3d77d9c) to head (8fdc528).
Report is 383 commits behind head on master.

Files with missing lines Patch % Lines
util/io/files/tar.go 80.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #19711      +/-   ##
==========================================
+ Coverage   50.69%   55.81%   +5.12%     
==========================================
  Files         315      320       +5     
  Lines       43381    44284     +903     
==========================================
+ Hits        21991    24719    +2728     
+ Misses      18882    17003    -1879     
- Partials     2508     2562      +54     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@blakepettersson
Copy link
Member

Can you create a unit test which proves that this is something which was previously (or currently is) an issue? From my testing it looks like the zip slip exploit is not exploitable in the first place, automated linters not withstanding.

e.g

	t.Run("will protect against zip slip exploit", func(t *testing.T) {
		tmpDir := createTmpDir(t)
		defer deleteTmpDir(t, tmpDir)

		// Create a malicious tar.gz archive in memory
		var buf bytes.Buffer
		gzw := gzip.NewWriter(&buf)
		tw := tar.NewWriter(gzw)

		// Add a malicious file entry that tries to escape the target directory
		maliciousPath := "../../../etc/passwd"
		hdr := &tar.Header{
			Name: maliciousPath,
			Mode: 0644,
			Size: int64(len("malicious content")),
		}
		if err := tw.WriteHeader(hdr); err != nil {
			t.Fatalf("Failed to write tar header: %v", err)
		}
		if _, err := tw.Write([]byte("malicious content")); err != nil {
			t.Fatalf("Failed to write tar content: %v", err)
		}

		// Close the tar and gzip writers
		if err := tw.Close(); err != nil {
			t.Fatalf("Failed to close tar writer: %v", err)
		}
		if err := gzw.Close(); err != nil {
			t.Fatalf("Failed to close gzip writer: %v", err)
		}

		err := files.Untgz(tmpDir, &buf, math.MaxInt64, false)
		assert.NoError(t, err)

		// Verify that the file was not created outside the temp directory
		targetPath := filepath.Join(tmpDir, maliciousPath)
		log.Printf(targetPath)
		if _, err := os.Stat(targetPath); err == nil {
			t.Fatalf("Malicious file was created: %s", targetPath)
		}
	})

Copy link
Member

@nitishfy nitishfy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Lint is failing still and the commits are not signed as well. I'd suggest start with fixing Lint , now that you've imported the strings package. In order to pass the DCO check, make sure your commits are signed.

@jsoref
Copy link
Member

jsoref commented Sep 25, 2024

I believe this is a false positive (see the related issue).

@jsoref jsoref closed this Sep 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Arbitrary file access during archive extraction ("Zip Slip")
4 participants