mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Python: Add taint-steps for MultiDictProxy
This commit is contained in:
@@ -13,6 +13,7 @@ private import semmle.python.frameworks.Fabric
|
||||
private import semmle.python.frameworks.Flask
|
||||
private import semmle.python.frameworks.Idna
|
||||
private import semmle.python.frameworks.Invoke
|
||||
private import semmle.python.frameworks.Multidict
|
||||
private import semmle.python.frameworks.MysqlConnectorPython
|
||||
private import semmle.python.frameworks.MySQLdb
|
||||
private import semmle.python.frameworks.Psycopg2
|
||||
|
||||
@@ -10,6 +10,7 @@ private import semmle.python.dataflow.new.TaintTracking
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.frameworks.internal.PoorMansFunctionResolution
|
||||
private import semmle.python.frameworks.Multidict
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
@@ -241,5 +242,10 @@ module AiohttpWebModel {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class AiohttpRequestMultiDictProxyInstances extends Multidict::MultiDictProxy::InstanceSource {
|
||||
AiohttpRequestMultiDictProxyInstances() {
|
||||
this.(DataFlow::AttrRead).getObject() = Request::instance() and
|
||||
this.(DataFlow::AttrRead).getAttributeName() in ["query", "headers"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
72
python/ql/src/semmle/python/frameworks/Multidict.qll
Normal file
72
python/ql/src/semmle/python/frameworks/Multidict.qll
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the `multidict` PyPI package.
|
||||
* See https://multidict.readthedocs.io/en/stable/.
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.dataflow.new.TaintTracking
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides models for the `multidict` PyPI package.
|
||||
* See https://multidict.readthedocs.io/en/stable/.
|
||||
*/
|
||||
module Multidict {
|
||||
/**
|
||||
* Provides models for a `MultiDictProxy` class:
|
||||
* - `multidict.MultiDictProxy`
|
||||
* - `multidict.CIMultiDictProxy`
|
||||
*
|
||||
* See https://multidict.readthedocs.io/en/stable/multidict.html#multidictproxy
|
||||
*/
|
||||
module MultiDictProxy {
|
||||
/**
|
||||
* A source of instances of `multidict.MultiDictProxy`, extend this class to model
|
||||
* new instances.
|
||||
*
|
||||
* This can include instantiations of the class, return values from function
|
||||
* calls, or a special parameter that will be set when functions are called by an external
|
||||
* library.
|
||||
*
|
||||
* Use `MultiDictProxy::instance()` predicate to get
|
||||
* references to instances of `multidict.MultiDictProxy`.
|
||||
*/
|
||||
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
|
||||
|
||||
/** Gets a reference to an instance of `multidict.MultiDictProxy`. */
|
||||
private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof InstanceSource
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `multidict.MultiDictProxy`. */
|
||||
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
|
||||
/**
|
||||
* Taint propagation for `multidict.MultiDictProxy`.
|
||||
*
|
||||
* See https://multidict.readthedocs.io/en/stable/multidict.html#multidictproxy
|
||||
*/
|
||||
class MultiDictProxyAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// Methods
|
||||
//
|
||||
// TODO: When we have tools that make it easy, model these properly to handle
|
||||
// `meth = obj.meth; meth()`. Until then, we'll use this more syntactic approach
|
||||
// (since it allows us to at least capture the most common cases).
|
||||
nodeFrom = instance() and
|
||||
exists(DataFlow::AttrRead attr | attr.getObject() = nodeFrom |
|
||||
// methods (non-async)
|
||||
attr.getAttributeName() in ["getone", "getall"] and
|
||||
nodeTo.(DataFlow::CallCfgNode).getFunction() = attr
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,8 +32,8 @@ async def test_taint(request: web.Request): # $ requestHandler
|
||||
request.query, # $ tainted
|
||||
request.query["key"], # $ tainted
|
||||
request.query.get("key"), # $ tainted
|
||||
request.query.getone("key"), # $ MISSING: tainted
|
||||
request.query.getall("key"), # $ MISSING: tainted
|
||||
request.query.getone("key"), # $ tainted
|
||||
request.query.getall("key"), # $ tainted
|
||||
request.query.keys(), # $ MISSING: tainted
|
||||
request.query.values(), # $ tainted
|
||||
request.query.items(), # $ tainted
|
||||
@@ -47,7 +47,7 @@ async def test_taint(request: web.Request): # $ requestHandler
|
||||
# an instance of the right class, and have the actual taint_test for that in a
|
||||
# different file!
|
||||
request.headers, # $ tainted
|
||||
request.headers.getone("key"), # $ MISSING: tainted
|
||||
request.headers.getone("key"), # $ tainted
|
||||
|
||||
# https://docs.python.org/3/library/asyncio-protocol.html#asyncio-transport
|
||||
# TODO
|
||||
|
||||
Reference in New Issue
Block a user