Skip to content

[BUG] util.Unzip copies archive entries without an output-size limit #4161

Description

@GG-Feng

Description

Description

util.Unzip rejects traversal entries with a destination path boundary check, but it copies each archive entry with io.Copy and does not appear to enforce a per-entry or total output-size limit.

Relevant code in internal/util/util.go:

path := filepath.Join(dest, f.Name)

if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
    return fmt.Errorf("illegal file path: %s", path)
}

_, err = io.Copy(f, rc)

Local validation output:

=== RUN   TestReproH12_UnzipBombAndTraversalMitigation
    repro_high_test.go:57:   (a) traversal rejected by HasPrefix: illegal file path: /tmp/TestReproH12_UnzipBombAndTraversalMitigation3808501357/outside.txt
    repro_high_test.go:76:   (b) 2182-byte zip -> 2097152 bytes via io.Copy with NO LimitReader
    repro_high_test.go:77: H12 = SPLIT: traversal mitigated (HasPrefix, FP), zip bomb real (io.Copy no cap, TP)
--- PASS: TestReproH12_UnzipBombAndTraversalMitigation (0.01s)

Expected behavior:

Unzip should enforce a reasonable per-entry and/or total extracted-size limit, or allow callers to provide one.

Actual behavior:

Each entry is copied until EOF, so extracted output size is controlled entirely by the archive contents.

Suggested fix:

Add an extraction size budget, such as a maximum bytes-per-entry and total extracted bytes. The copy path could use a bounded reader/writer and return an error once the configured limit is exceeded.

Environment

Environment

  • Version: tested at commit 77de728
  • OS: Linux / Docker
  • Terminal: N/A

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions