Skip to content

Commit 3470cd3

Browse files
Eshani ParulekarEshani Parulekar
authored andcommitted
feat(G304): add os.Root remediation hint (Autofix) when Go >= 1.24
1 parent 3ead143 commit 3470cd3

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

rules/readfile.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ func (r *readfile) trackJoinAssignStmt(node *ast.AssignStmt, c *gosec.Context) {
111111
}
112112
}
113113

114+
// osRootSuggestion returns an Autofix suggesting the use of os.Root where supported
115+
// to constrain file access under a fixed directory and mitigate traversal risks.
116+
func (r *readfile) osRootSuggestion() string {
117+
major, minor, _ := gosec.GoVersion()
118+
if major == 1 && minor >= 24 {
119+
return "Consider using os.Root to scope file access under a fixed root (Go >=1.24). Prefer root.Open/root.Stat over os.Open/os.Stat to prevent directory traversal."
120+
}
121+
return ""
122+
}
123+
114124
// isSafeJoin checks if path is baseDir + filepath.Clean(fn) joined.
115125
// improvements over earlier naive version:
116126
// - allow baseDir as a BasicLit or as an identifier that resolves to a string constant
@@ -193,7 +203,11 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
193203
}
194204
// If the argument is a Join call but not safe per above, flag it (as before)
195205
if r.isJoinFunc(callExpr, c) {
196-
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
206+
iss := c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence)
207+
if s := r.osRootSuggestion(); s != "" {
208+
iss.Autofix = s
209+
}
210+
return iss, nil
197211
}
198212
}
199213

@@ -211,7 +225,11 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
211225
return nil, nil
212226
}
213227
// join exists but is not safe: flag it
214-
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
228+
iss := c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence)
229+
if s := r.osRootSuggestion(); s != "" {
230+
iss.Autofix = s
231+
}
232+
return iss, nil
215233
}
216234
}
217235
}
@@ -221,7 +239,11 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
221239
if binExp, ok := arg.(*ast.BinaryExpr); ok {
222240
// resolve all found identities from the BinaryExpr
223241
if _, ok := gosec.FindVarIdentities(binExp, c); ok {
224-
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
242+
iss := c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence)
243+
if s := r.osRootSuggestion(); s != "" {
244+
iss.Autofix = s
245+
}
246+
return iss, nil
225247
}
226248
}
227249

@@ -231,7 +253,11 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
231253
if _, ok := obj.(*types.Var); ok &&
232254
!gosec.TryResolve(ident, c) &&
233255
!r.isFilepathClean(ident, c) {
234-
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
256+
iss := c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence)
257+
if s := r.osRootSuggestion(); s != "" {
258+
iss.Autofix = s
259+
}
260+
return iss, nil
235261
}
236262
}
237263
}

0 commit comments

Comments
 (0)