diff --git a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql index afa675c7f7b2..77e952535c2b 100644 --- a/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql +++ b/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql @@ -15,6 +15,7 @@ import java import semmle.code.java.security.CommandLineQuery import semmle.code.java.security.ExternalProcess +private import semmle.code.java.dataflow.internal.ModelExclusions /** * Strings that are known to be sane by some simple local analysis. Such strings @@ -26,6 +27,27 @@ predicate saneString(Expr expr) { or expr instanceof NullLiteral or + // Numeric literals cannot contain shell metacharacters. + expr instanceof IntegerLiteral + or + expr instanceof LongLiteral + or + expr instanceof FloatingPointLiteral + or + expr instanceof DoubleLiteral + or + // Expressions of primitive or boxed numeric type cannot contain shell metacharacters + // when converted to strings (e.g., via string concatenation). + expr.getType() instanceof PrimitiveType + or + expr.getType() instanceof BoxedType + or + // Enum constants have programmer-controlled string representations. + expr.(VarAccess).getVariable() instanceof EnumConstant + or + // Compile-time constant expressions are fully controlled by the programmer. + expr instanceof CompileTimeConstantExpr + or exists(Variable var | var.getAnAccess() = expr and exists(var.getAnAssignedValue()) | forall(Expr other | var.getAnAssignedValue() = other | saneString(other)) ) @@ -48,5 +70,8 @@ predicate builtFromUncontrolledConcat(Expr expr) { from StringArgumentToExec argument where builtFromUncontrolledConcat(argument) and - not execIsTainted(_, _, argument) + not execIsTainted(_, _, argument) and + // Exclude test files: command concatenation in tests is typically for test setup + // and does not represent a real security vulnerability. + not isInTestFile(argument.getFile()) select argument, "Command line is built with string concatenation." diff --git a/java/ql/src/change-notes/2026-06-14-exec-unescaped-improved-sane-string.md b/java/ql/src/change-notes/2026-06-14-exec-unescaped-improved-sane-string.md new file mode 100644 index 000000000000..d94e465f7a16 --- /dev/null +++ b/java/ql/src/change-notes/2026-06-14-exec-unescaped-improved-sane-string.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- + +* The `java/concatenated-command-line` query now has an improved `saneString` predicate that recognizes numeric literals, expressions of primitive/boxed numeric types, enum constants, and compile-time constant expressions as safe values that cannot contain shell metacharacters. Results in test files are also excluded. This significantly reduces false positives where command lines are built with safe numeric values or known constants.