From fb40914ba7866d6453043ad278b2b3a70815c5f1 Mon Sep 17 00:00:00 2001 From: Kiro Agent <244629292+kiro-agent@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:52:58 +0000 Subject: [PATCH] feat: consolidate saneString improvements using controlledString + test exclusion Replace the saneString predicate body with controlledString (from the ControlledString library) and CompileTimeConstantExpr to reduce false positives. Also exclude results in test files using isInTestFile from ModelExclusions. This consolidates the approaches from PRs #5 and #10 into a single coherent change. --- .../src/Security/CWE/CWE-078/ExecUnescaped.ql | 19 +++++++++---------- .../2026-06-15-exec-unescaped-consolidated.md | 4 ++++ 2 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 java/ql/src/change-notes/2026-06-15-exec-unescaped-consolidated.md diff --git a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql index afa675c7f7b2..99f3e15f7e05 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql +++ b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql @@ -15,20 +15,18 @@ import java import semmle.code.java.security.CommandLineQuery import semmle.code.java.security.ExternalProcess +import semmle.code.java.security.ControlledString +import semmle.code.java.dataflow.internal.ModelExclusions /** - * Strings that are known to be sane by some simple local analysis. Such strings - * do not need to be escaped, because the programmer can predict what the string - * has in it. + * Strings that are known to be sane (controlled or compile-time constant). + * Such strings do not need to be escaped, because the programmer can predict + * what the string has in it. */ predicate saneString(Expr expr) { - expr instanceof StringLiteral + controlledString(expr) or - expr instanceof NullLiteral - or - exists(Variable var | var.getAnAccess() = expr and exists(var.getAnAssignedValue()) | - forall(Expr other | var.getAnAssignedValue() = other | saneString(other)) - ) + expr instanceof CompileTimeConstantExpr } predicate builtFromUncontrolledConcat(Expr expr) { @@ -48,5 +46,6 @@ predicate builtFromUncontrolledConcat(Expr expr) { from StringArgumentToExec argument where builtFromUncontrolledConcat(argument) and - not execIsTainted(_, _, argument) + not execIsTainted(_, _, argument) and + not isInTestFile(argument.getFile()) select argument, "Command line is built with string concatenation." diff --git a/java/ql/src/change-notes/2026-06-15-exec-unescaped-consolidated.md b/java/ql/src/change-notes/2026-06-15-exec-unescaped-consolidated.md new file mode 100644 index 000000000000..4589b2e8e03d --- /dev/null +++ b/java/ql/src/change-notes/2026-06-15-exec-unescaped-consolidated.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `java/concatenated-command-line` query now uses `controlledString` and `CompileTimeConstantExpr` instead of the previous `saneString` heuristic, reducing false positives for expressions that are known to be safe. Additionally, results in test files are now excluded.