Merge pull request #13782 from jorgectf/jorgectf/shlex-quote

Python: Add `shlex.quote` as `py/shell-command-constructed-from-input` sanitizer
This commit is contained in:
yoff
2023-08-31 21:08:58 +02:00
committed by GitHub
4 changed files with 24 additions and 2 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added `shlex.quote` as a sanitizer for the `py/shell-command-constructed-from-input` query.

View File

@@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import CommandInjectionCustomizations::CommandInjection as CommandInjection
private import semmle.python.Concepts as Concepts
private import semmle.python.ApiGraphs
/**
* Module containing sources, sinks, and sanitizers for shell command constructed from library input.
@@ -17,6 +18,9 @@ module UnsafeShellCommandConstruction {
/** A source for shell command constructed from library input vulnerabilities. */
abstract class Source extends DataFlow::Node { }
/** A sanitizer for shell command constructed from library input vulnerabilities. */
abstract class Sanitizer extends DataFlow::Node { }
private import semmle.python.frameworks.Setuptools
/** An input parameter to a gem seen as a source. */
@@ -156,4 +160,13 @@ module UnsafeShellCommandConstruction {
override DataFlow::Node getStringConstruction() { result = formatCall }
}
/**
* A call to `shlex.quote`, considered as a sanitizer.
*/
class ShlexQuoteAsSanitizer extends Sanitizer, DataFlow::Node {
ShlexQuoteAsSanitizer() {
this = API::moduleImport("shlex").getMember("quote").getACall().getArg(0)
}
}
}

View File

@@ -24,7 +24,8 @@ class Configuration extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) {
node instanceof CommandInjection::Sanitizer // using all sanitizers from `rb/command-injection`
node instanceof Sanitizer or
node instanceof CommandInjection::Sanitizer // using all sanitizers from `py/command-injection`
}
// override to require the path doesn't have unmatched return steps

View File

@@ -46,4 +46,8 @@ def subprocess_flag (name):
subprocess.Popen("ping " + name, shell=unknownValue) # OK - shell assumed to be False
def intentional(command):
os.system("fish -ic " + command) # $result=OK - intentional
os.system("fish -ic " + command) # $result=OK - intentional
import shlex
def unsafe_shell_sanitized(name):
os.system("ping " + shlex.quote(name)) # $result=OK - sanitized