From e77eced4a399e4d0851c1efdfdfd5323417aaffa Mon Sep 17 00:00:00 2001 From: Dave Thompson Date: Wed, 16 Sep 2026 17:59:33 -0400 Subject: [PATCH] fix: disposition gosec G703 findings on zip extraction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record SDR-006: the three path-traversal flags on extractZip are false positives — every sink operates on a prefix-contained path proven by the zip-slip rejection tests. Annotate the three sites. Verification: gosec at latest and 2.24.7 report 0 issues; make precommit green. Generated by Muse Spark running Muse Code under supervision of [@3leapsdave](https://github.com/3leapsdave) Co-Authored-By: Muse Spark Role: devlead Committer-of-Record: Dave Thompson [@3leapsdave] --- docs/security/suppressions/gosec.md | 51 +++++++++++++++++++++++++++++ main.go | 6 ++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/docs/security/suppressions/gosec.md b/docs/security/suppressions/gosec.md index d49e7a9..7a4db56 100644 --- a/docs/security/suppressions/gosec.md +++ b/docs/security/suppressions/gosec.md @@ -168,6 +168,56 @@ The provenance file (JSON metadata about a download) is written with 0644 permis --- +## SDR-006: Contained Extraction Paths (G703) + +**Rule:** G703 - Path traversal via taint analysis +**Severity:** High +**Instances:** 3 +**Decision:** Suppress with `#nosec G703 -- SDR-006` + +### Context + +G703 flags `os.MkdirAll` and `os.OpenFile` sinks in `extractZip` whose path +argument is tainted by archive entry names, warning of zip-slip path traversal. + +### Why Suppression is Appropriate + +Every flagged sink operates only on `destPathClean`, which cannot escape the +extraction directory: + +1. **Entry names are normalized and pre-filtered**: `filepath.FromSlash` + + `filepath.Clean`; `.` skipped; `..`, absolute paths, and volume names are + hard errors before any path is built. + +2. **Joined path must stay under the prefix**: after `filepath.Join` + + `filepath.Clean`, a path that is neither the extraction dir itself nor + prefixed by it is a hard error. The analyzer cannot follow this + string-prefix containment proof, so it reports the residual taint at high + confidence despite the runtime gate. + +3. **No symlink or special-file escape**: symlinks and non-regular files are + refused before any directory creation or file write. + +### Proof + +Covered by maintained regression tests, not by inspection alone: + +- `TestExtractZipRejectsZipSlip` (`../evil` rejected; asserts nothing is + written outside the extraction dir) +- `TestExtractZipRejectsAbsolutePaths` +- `TestExtractZipRejectsSymlinks` +- `TestExtractZipNestedPaths` (legitimate nested paths still extract) + +### Affected Locations + +| File | Function | Purpose | +|------|----------|---------| +| main.go | extractZip | MkdirAll for entry dir (contained path) | +| main.go | extractZip | MkdirAll for entry parent dir (contained path) | +| main.go | extractZip | OpenFile for entry content (contained path) | + +--- + ## Suppression Audit Log | Date | SDR | Action | Author | @@ -177,3 +227,4 @@ The provenance file (JSON metadata about a download) is written with 0644 permis | 2026-01-10 | SDR-003 | Created | Claude Opus 4.5 | | 2026-01-10 | SDR-004 | Created | Claude Opus 4.5 | | 2026-01-10 | SDR-005 | Created | Claude Opus 4.5 | +| 2026-09-16 | SDR-006 | Created | Muse Spark | diff --git a/main.go b/main.go index 1ce391d..f14795e 100644 --- a/main.go +++ b/main.go @@ -3435,14 +3435,14 @@ func extractZip(zipPath, extractDir string) error { } if f.FileInfo().IsDir() { - // #nosec G301 -- SDR-002: tar extraction dir + // #nosec G301,G703 -- SDR-002: tar extraction dir; SDR-006: prefix-contained path if err := os.MkdirAll(destPathClean, 0o755); err != nil { return fmt.Errorf("mkdir %s: %w", destPathClean, err) } continue } - // #nosec G301 -- SDR-002: tar extraction dir + // #nosec G301,G703 -- SDR-002: tar extraction dir; SDR-006: prefix-contained path if err := os.MkdirAll(filepath.Dir(destPathClean), 0o755); err != nil { return fmt.Errorf("mkdir %s: %w", filepath.Dir(destPathClean), err) } @@ -3452,7 +3452,7 @@ func extractZip(zipPath, extractDir string) error { return fmt.Errorf("open %s in zip: %w", f.Name, err) } - // #nosec G302 -- SDR-003: extracted file permissions + // #nosec G302,G703 -- SDR-003: extracted file permissions; SDR-006: prefix-contained path out, err := os.OpenFile(destPathClean, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644) if err != nil { _ = rc.Close()