diff --git a/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll index b1001b372e2..479907d2052 100644 --- a/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll @@ -42,6 +42,16 @@ module CommandInjection { SystemCommandExecutionSink() { exists(SystemCommandExecution c | c.isShellInterpreted(this)) } } + /** + * A call to `String#shellescape` sanitizes its input. + */ + class ShellwordsEscapeAsSanitizer extends Sanitizer { + ShellwordsEscapeAsSanitizer() { + // The `Shellwords.shellescape` method is also added as `String#shellescape`. + this.(DataFlow::CallNode).getMethodName() = "shellescape" + } + } + private class ExternalCommandInjectionSink extends Sink { ExternalCommandInjectionSink() { ModelOutput::sinkNode(this, "command-injection") } } diff --git a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected index 34d75aa6431..2173fed576a 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected @@ -13,7 +13,6 @@ | CommandInjection.rb:83:14:83:34 | "echo #{...}" | CommandInjection.rb:82:23:82:33 | blah_number | CommandInjection.rb:83:14:83:34 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:82:23:82:33 | blah_number | user-provided value | | CommandInjection.rb:92:14:92:39 | "echo #{...}" | CommandInjection.rb:92:22:92:37 | ...[...] | CommandInjection.rb:92:14:92:39 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:92:22:92:37 | ...[...] | user-provided value | | CommandInjection.rb:105:16:105:28 | "cat #{...}" | CommandInjection.rb:104:16:104:21 | call to params | CommandInjection.rb:105:16:105:28 | "cat #{...}" | This command depends on a $@. | CommandInjection.rb:104:16:104:21 | call to params | user-provided value | -| CommandInjection.rb:107:16:107:40 | "cat #{...}" | CommandInjection.rb:104:16:104:21 | call to params | CommandInjection.rb:107:16:107:40 | "cat #{...}" | This command depends on a $@. | CommandInjection.rb:104:16:104:21 | call to params | user-provided value | | CommandInjection.rb:112:33:112:44 | ...[...] | CommandInjection.rb:112:33:112:38 | call to params | CommandInjection.rb:112:33:112:44 | ...[...] | This command depends on a $@. | CommandInjection.rb:112:33:112:38 | call to params | user-provided value | | CommandInjection.rb:114:41:114:56 | "#{...}" | CommandInjection.rb:114:44:114:49 | call to params | CommandInjection.rb:114:41:114:56 | "#{...}" | This command depends on a $@. | CommandInjection.rb:114:44:114:49 | call to params | user-provided value | edges @@ -37,11 +36,8 @@ edges | CommandInjection.rb:82:23:82:33 | blah_number | CommandInjection.rb:83:14:83:34 | "echo #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:92:22:92:37 | ...[...] | CommandInjection.rb:92:14:92:39 | "echo #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:104:9:104:12 | file | CommandInjection.rb:105:16:105:28 | "cat #{...}" | provenance | AdditionalTaintStep | -| CommandInjection.rb:104:9:104:12 | file | CommandInjection.rb:107:23:107:26 | file | provenance | | | CommandInjection.rb:104:16:104:21 | call to params | CommandInjection.rb:104:16:104:28 | ...[...] | provenance | | | CommandInjection.rb:104:16:104:28 | ...[...] | CommandInjection.rb:104:9:104:12 | file | provenance | | -| CommandInjection.rb:107:23:107:26 | file | CommandInjection.rb:107:23:107:38 | call to shellescape | provenance | | -| CommandInjection.rb:107:23:107:38 | call to shellescape | CommandInjection.rb:107:16:107:40 | "cat #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:112:33:112:38 | call to params | CommandInjection.rb:112:33:112:44 | ...[...] | provenance | Sink:MaD:1 | | CommandInjection.rb:114:44:114:49 | call to params | CommandInjection.rb:114:44:114:54 | ...[...] | provenance | | | CommandInjection.rb:114:44:114:54 | ...[...] | CommandInjection.rb:114:41:114:56 | "#{...}" | provenance | AdditionalTaintStep Sink:MaD:2 | @@ -78,14 +74,9 @@ nodes | CommandInjection.rb:104:16:104:21 | call to params | semmle.label | call to params | | CommandInjection.rb:104:16:104:28 | ...[...] | semmle.label | ...[...] | | CommandInjection.rb:105:16:105:28 | "cat #{...}" | semmle.label | "cat #{...}" | -| CommandInjection.rb:107:16:107:40 | "cat #{...}" | semmle.label | "cat #{...}" | -| CommandInjection.rb:107:23:107:26 | file | semmle.label | file | -| CommandInjection.rb:107:23:107:38 | call to shellescape | semmle.label | call to shellescape | | CommandInjection.rb:112:33:112:38 | call to params | semmle.label | call to params | | CommandInjection.rb:112:33:112:44 | ...[...] | semmle.label | ...[...] | | CommandInjection.rb:114:41:114:56 | "#{...}" | semmle.label | "#{...}" | | CommandInjection.rb:114:44:114:49 | call to params | semmle.label | call to params | | CommandInjection.rb:114:44:114:54 | ...[...] | semmle.label | ...[...] | subpaths -testFailures -| CommandInjection.rb:107:16:107:40 | "cat #{...}" | Unexpected result: Alert |