rootwrite

package
v0.82.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package rootwrite catches writes whose containment under a root is resolved lexically only: os.WriteFile / os.Create / os.OpenFile(write flag) / os.MkdirAll on a path built under a root — filepath.Join, or a flat `root + "/" + x` concatenation — where the root is a caller-supplied parameter or field — with no filepath.EvalSymlinks on that path's chain — plus the archive twin: zip.Writer entry names assembled from a parameter with no path.Clean on the entry-name chain.

The bug class: lexical prefix checks cannot see symlinks. Probes TestApplyRefusesSymlinkEscape (framework/contracts report.go containedPath/Apply, fixed in 77fdbaf4: a diagnostic whose path crossed a symlinked directory was written outside the project root even though Join+HasPrefix said "contained") and TestPackZipPrefixCannotEscapeDir (framework/sdk zip.go PackZip, fixed in 1501a555: a "../" prefix placed archive entries above the target directory on extract).

Every gate is per write and on the write's own dataflow: resolution, validation, and cleaning on an unrelated path (or consulted for a boolean and leaving the path components untouched) gate nothing.

Silent postures, deliberately:

  • the write's path (or a component of it, or the Join's root) is bound to a filepath.EvalSymlinks result, or an EvalSymlinks ran on this path expression — resolution on the chain (the fix posture);
  • calls to symlink-named guards (EnsureNoSymlinkPath): resolution by another name;
  • a sanitizer/validator whose RESULT replaces a joined component (sanitize(name) feeding the Join): the component that reaches the disk passed through it. A validator consulted for its boolean cannot see symlinks and gates nothing;
  • roots that are not parameters or root/base/dir-named fields (a constant or computed root has no caller-controlled boundary to defend), including a rooty local resolved through one;
  • builds whose every non-root argument is a literal — nothing caller-controlled is appended under the root. This holds at the helper hop too: a same-package containment helper called with literal-only non-root arguments stays quiet, and a helper whose body resolves symlinks is the fix posture;
  • temp roots: a local bound to os.MkdirTemp or t.TempDir is throwaway by construction;
  • zip entry names assembled only from literals or non-parameter values (a wrapper forwarding its own name parameter composes nothing), and entry names whose assembly is bound to a path.Clean / filepath.Clean result;
  • reads (os.Open, os.ReadFile, O_RDONLY) by construction;
  • _test.go files.

Index

Constants

This section is empty.

Variables

View Source
var Analyzer = &analysis.Analyzer{
	Name: "rootwrite",
	Doc:  "forbids writes under a root whose containment is lexical only: resolve with filepath.EvalSymlinks, and path.Clean zip entry names",
	Run:  run,
}

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL