-
-
Notifications
You must be signed in to change notification settings - Fork 0
fix(scan): apply contextual shell suppression and patch Bandit #737
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
base: main
Are you sure you want to change the base?
Changes from all commits
6dc51b9
68fe8fe
8936d57
ae7fd12
dc7cecb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -214,7 +214,9 @@ defmodule Hypatia.ScannerSuppression do | |
| secret — it is a reference to the secret store). Centralised so future | ||
| rules can opt in via the same predicate. | ||
| """ | ||
| def context_safe_line?("secret_detected", line) do | ||
| def context_safe_line?(rule_type, line), do: context_safe_line?(rule_type, line, nil) | ||
|
|
||
| def context_safe_line?("secret_detected", line, _line_number) do | ||
| Regex.match?(gha_secret_ref_re(), line) or | ||
| Regex.match?(gha_vars_ref_re(), line) or | ||
| Regex.match?(shell_param_expansion_re(), line) or | ||
|
|
@@ -232,14 +234,17 @@ defmodule Hypatia.ScannerSuppression do | |
| # pipe-to-shell sits inside the quotes or outside them. So the quoted | ||
| # segments are removed and the pattern re-tested against what remains: if it | ||
| # no longer matches, every match was inside a string. | ||
| def context_safe_line?("shell_download_then_run", line) when is_binary(line) do | ||
| def context_safe_line?("shell_download_then_run", line, line_number) when is_binary(line) do | ||
| stripped_line = String.trim_leading(line) | ||
| stripped = strip_quoted_segments(line) | ||
|
|
||
| Regex.match?(download_then_run_re(), line) and | ||
| not Regex.match?(download_then_run_re(), stripped) | ||
| (line_number != 1 and String.starts_with?(stripped_line, "#")) or | ||
| (Regex.match?(download_then_run_re(), line) and | ||
| not Regex.match?(download_then_run_re(), stripped) and | ||
| not executable_shell_evaluation?(stripped)) | ||
| end | ||
|
|
||
| def context_safe_line?(_rule_type, _line), do: false | ||
| def context_safe_line?(_rule_type, _line, _line_number), do: false | ||
|
|
||
| @doc """ | ||
| Return true if an inline `hypatia: allow` directive on `line` or | ||
|
|
@@ -284,6 +289,17 @@ defmodule Hypatia.ScannerSuppression do | |
| defp download_then_run_re, | ||
| do: ~r/\b(?:curl|wget)\b[^\n|;]*\|\s*(?:sh|bash)\b/ | ||
|
|
||
| # `sh -c '…'` and an `env -S` shebang pass their quoted argument to a | ||
| # shell, so it is executable rather than display-only text. Check the | ||
| # quote-stripped line for the invocation: this retains those arguments | ||
| # without treating an `echo` or `printf` argument as executable. | ||
| defp executable_shell_evaluation?(stripped_line) do | ||
| Regex.match?( | ||
| ~r/^\s*(?:(?:#!\s*\S*|env)\s+-S\s+)?(?:sh|bash)\b(?:\s+-[A-Za-z]+)*\s+-[A-Za-z]*c[A-Za-z]*\b/, | ||
| stripped_line | ||
|
Comment on lines
+298
to
+299
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift Keep executable shell contexts out of the suppression path.
🤖 Prompt for AI Agents |
||
| ) | ||
| end | ||
|
|
||
| # Remove the CONTENTS of single- and double-quoted segments, leaving the | ||
| # quotes, so that anything written inside a string cannot satisfy a pattern | ||
| # tested against the remainder. Escaped quotes are honoured. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Handle inline shell comments.
String.starts_with?(stripped_line, "#")recognises only a full-line comment. Forecho done # curl https://example.com/install.sh | sh, the match is inside the trailing shell comment, butcontext_safe_line?/3returnsfalseandCodeSafety.scan_content/2reports a false positive. Strip only an unquoted trailing#comment before applying this rule, while retaining real commands and#inside quoted text.🤖 Prompt for AI Agents