Merge branch 'main' of github.com:github/codeql into python/promote-xpath-injection

This commit is contained in:
Rasmus Lerchedahl Petersen
2022-03-02 13:14:08 +01:00
1234 changed files with 113662 additions and 51952 deletions

View File

@@ -222,26 +222,6 @@
],
"description": "Type tracking class (select full class path before inserting)",
},
"foo": {
"scope": "ql",
"prefix": "foo",
"body": [
" /**",
" * Taint propagation for `$1`.",
" */",
" private class InstanceTaintSteps extends InstanceTaintStepsHelper {",
" InstanceTaintSteps() { this = \"$1\" }",
"",
" override DataFlow::Node getInstance() { result = instance() }",
"",
" override string getAttributeName() { none() }",
"",
" override string getMethodName() { none() }",
"",
" override string getAsyncMethodName() { none() }",
" }",
],
},
"API graph .getMember chain": {
"scope": "ql",
"prefix": "api graph .getMember chain",
@@ -250,4 +230,22 @@
],
"description": "API graph .getMember chain (select full path before inserting)",
},
"debug partial flow": {
"scope": "ql",
"prefix": "debug partial flow",
"body": [
"// put the line below inside the configuration",
"// override int explorationLimit() { result = 5 }",
"// and then run quick evaluation on the predicate below",
"// (and potentially limit the set of sources)",
"predicate debugPartialFlow(Location loc, DataFlow::PartialPathNode node, int dist) {",
" loc = node.getNode().getLocation() and",
" exists(loc.getFile().getRelativePath()) and",
" exists(Configuration config, DataFlow::PartialPathNode source |",
" config.hasPartialFlow(source, node, dist)",
" )",
"}",
],
"description": "debug partial flow",
},
}

View File

@@ -0,0 +1,5 @@
name: codeql/python-consistency-queries
groups: [python, test, consistency-queries]
dependencies:
codeql/python-all: "*"
extractor: python

View File

@@ -1,3 +1,18 @@
## 0.0.10
### Deprecated APIs
* The old points-to based modeling has been deprecated. Use the new type-tracking/API-graphs based modeling instead.
## 0.0.9
## 0.0.8
### Deprecated APIs
* Moved the files defining regex injection configuration and customization, instead of `import semmle.python.security.injection.RegexInjection` please use `import semmle.python.security.dataflow.RegexInjection` (the same for `RegexInjectionCustomizations`).
* The `codeql/python-upgrades` CodeQL pack has been removed. All upgrades scripts have been merged into the `codeql/python-all` CodeQL pack.
## 0.0.7
## 0.0.6

View File

@@ -1,4 +0,0 @@
---
category: deprecated
---
* The `codeql/python-upgrades` CodeQL pack has been removed. All upgrades scripts have been merged into the `codeql/python-all` CodeQL pack.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Improved analysis of attributes for data-flow and taint tracking queries, so `getattr`/`setattr` are supported, and a write to an attribute properly stops flow for the old value in that attribute.
* Added post-update nodes (`DataFlow::PostUpdateNode`) for arguments in calls that can't be resolved.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Fixed taint propagation for attribute assignment. In the assignment `x.foo = tainted` we no longer treat the entire object `x` as tainted, just because the attribute `foo` contains tainted data. This leads to slightly fewer false positives.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The regular expression parser now groups sequences of normal characters. This reduces the number of instances of `RegExpNormalChar`.

View File

@@ -0,0 +1,5 @@
## 0.0.10
### Deprecated APIs
* The old points-to based modeling has been deprecated. Use the new type-tracking/API-graphs based modeling instead.

View File

@@ -1,4 +1,6 @@
---
category: deprecated
---
## 0.0.8
### Deprecated APIs
* Moved the files defining regex injection configuration and customization, instead of `import semmle.python.security.injection.RegexInjection` please use `import semmle.python.security.dataflow.RegexInjection` (the same for `RegexInjectionCustomizations`).
* The `codeql/python-upgrades` CodeQL pack has been removed. All upgrades scripts have been merged into the `codeql/python-all` CodeQL pack.

View File

@@ -0,0 +1 @@
## 0.0.9

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.0.7
lastReleaseVersion: 0.0.10

View File

@@ -1,5 +1,5 @@
name: codeql/python-all
version: 0.0.8-dev
version: 0.0.11-dev
groups: python
dbscheme: semmlecode.python.dbscheme
extractor: python

View File

@@ -552,6 +552,44 @@ module XML {
}
}
/** Provides classes for modeling LDAP-related APIs. */
module LDAP {
/**
* A data-flow node that executes an LDAP query.
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `LDAPQuery::Range` instead.
*/
class LdapExecution extends DataFlow::Node {
LdapExecution::Range range;
LdapExecution() { this = range }
/** Gets the argument containing the filter string. */
DataFlow::Node getFilter() { result = range.getFilter() }
/** Gets the argument containing the base DN. */
DataFlow::Node getBaseDn() { result = range.getBaseDn() }
}
/** Provides classes for modeling new LDAP query execution-related APIs. */
module LdapExecution {
/**
* A data-flow node that executes an LDAP query.
*
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `LDAPQuery` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets the argument containing the filter string. */
abstract DataFlow::Node getFilter();
/** Gets the argument containing the base DN. */
abstract DataFlow::Node getBaseDn();
}
}
}
/**
* A data-flow node that escapes meta-characters, which could be used to prevent
* injection attacks.
@@ -609,8 +647,20 @@ module Escaping {
/** Gets the escape-kind for escaping a string so it can safely be included in HTML. */
string getHtmlKind() { result = "html" }
/** Gets the escape-kind for escaping a string so it can safely be included in HTML. */
/** Gets the escape-kind for escaping a string so it can safely be included in a regular expression. */
string getRegexKind() { result = "regex" }
/**
* Gets the escape-kind for escaping a string so it can safely be used as a
* distinguished name (DN) in an LDAP search.
*/
string getLdapDnKind() { result = "ldap_dn" }
/**
* Gets the escape-kind for escaping a string so it can safely be used as a
* filter in an LDAP search.
*/
string getLdapFilterKind() { result = "ldap_filter" }
// TODO: If adding an XML kind, update the modeling of the `MarkupSafe` PyPI package.
//
// Technically it claims to escape for both HTML and XML, but for now we don't have
@@ -635,9 +685,28 @@ class RegexEscaping extends Escaping {
RegexEscaping() { range.getKind() = Escaping::getRegexKind() }
}
/**
* An escape of a string so it can be safely used as a distinguished name (DN)
* in an LDAP search.
*/
class LdapDnEscaping extends Escaping {
LdapDnEscaping() { range.getKind() = Escaping::getLdapDnKind() }
}
/**
* An escape of a string so it can be safely used as a filter in an LDAP search.
*/
class LdapFilterEscaping extends Escaping {
LdapFilterEscaping() { range.getKind() = Escaping::getLdapFilterKind() }
}
/** Provides classes for modeling HTTP-related APIs. */
module HTTP {
import semmle.python.web.HttpConstants
/** Gets an HTTP verb, in upper case */
string httpVerb() { result in ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"] }
/** Gets an HTTP verb, in lower case */
string httpVerbLower() { result = httpVerb().toLowerCase() }
/** Provides classes for modeling HTTP servers. */
module Server {

View File

@@ -22,6 +22,8 @@ private import semmle.python.frameworks.FlaskSqlAlchemy
private import semmle.python.frameworks.Idna
private import semmle.python.frameworks.Invoke
private import semmle.python.frameworks.Jmespath
private import semmle.python.frameworks.Ldap
private import semmle.python.frameworks.Ldap3
private import semmle.python.frameworks.Libxml2
private import semmle.python.frameworks.Lxml
private import semmle.python.frameworks.MarkupSafe

View File

@@ -39,7 +39,12 @@ newtype TRegExpParent =
/** A special character */
TRegExpSpecialChar(Regex re, int start, int end) { re.specialCharacter(start, end, _) } or
/** A normal character */
TRegExpNormalChar(Regex re, int start, int end) { re.normalCharacter(start, end) } or
TRegExpNormalChar(Regex re, int start, int end) {
re.normalCharacterSequence(start, end)
or
re.escapedCharacter(start, end) and
not re.specialCharacter(start, end, _)
} or
/** A back reference */
TRegExpBackRef(Regex re, int start, int end) { re.backreference(start, end) }

View File

@@ -204,6 +204,8 @@ abstract class AttrRead extends AttrRef, Node, LocalSourceNode { }
private class AttributeReadAsAttrRead extends AttrRead, CfgNode {
override AttrNode node;
AttributeReadAsAttrRead() { node.isLoad() }
override Node getObject() { result.asCfgNode() = node.getObject() }
override ExprNode getAttributeNameExpr() {

View File

@@ -126,7 +126,7 @@ module syntheticPostUpdateNode {
* Certain arguments, such as implicit self arguments are already post-update nodes
* and should not have an extra node synthesised.
*/
ArgumentNode argumentPreUpdateNode() {
Node argumentPreUpdateNode() {
result = any(FunctionCall c).getArg(_)
or
// Avoid argument 0 of method calls as those have read post-update nodes.
@@ -136,6 +136,11 @@ module syntheticPostUpdateNode {
or
// Avoid argument 0 of class calls as those have non-synthetic post-update nodes.
exists(ClassCall c, int n | n > 0 | result = c.getArg(n))
or
// any argument of any call that we have not been able to resolve
exists(CallNode call | not call = any(DataFlowCall c).getNode() |
result.(CfgNode).getNode() in [call.getArg(_), call.getArgByName(_)]
)
}
/** An object might have its value changed after a store. */
@@ -704,7 +709,7 @@ newtype TDataFlowCall =
TFunctionCall(CallNode call) { call = any(FunctionValue f).getAFunctionCall() } or
/** Bound methods need to make room for the explicit self parameter */
TMethodCall(CallNode call) { call = any(FunctionValue f).getAMethodCall() } or
TClassCall(CallNode call) { call = any(ClassValue c).getACall() } or
TClassCall(CallNode call) { call = any(ClassValue c | not c.isAbsent()).getACall() } or
TSpecialCall(SpecialMethodCallNode special)
/** Represents a call. */
@@ -1002,7 +1007,7 @@ predicate listStoreStep(CfgNode nodeFrom, ListElementContent c, CfgNode nodeTo)
}
/** Data flows from an element of a set to the set. */
predicate setStoreStep(CfgNode nodeFrom, ListElementContent c, CfgNode nodeTo) {
predicate setStoreStep(CfgNode nodeFrom, SetElementContent c, CfgNode nodeTo) {
// Set
// `{..., 42, ...}`
// nodeFrom is `42`, cfg node
@@ -1067,19 +1072,18 @@ predicate comprehensionStoreStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
}
/**
* Holds if `nodeFrom` flows into an attribute (corresponding to `c`) of `nodeTo` via an attribute assignment.
* Holds if `nodeFrom` flows into the attribute `c` of `nodeTo` via an attribute assignment.
*
* For example, in
* ```python
* obj.foo = x
* ```
* data flows from `x` to (the post-update node for) `obj` via assignment to `foo`.
* data flows from `x` to the attribute `foo` of (the post-update node for) `obj`.
*/
predicate attributeStoreStep(CfgNode nodeFrom, AttributeContent c, PostUpdateNode nodeTo) {
exists(AttrNode attr |
nodeFrom.asCfgNode() = attr.(DefinitionNode).getValue() and
attr.getName() = c.getAttribute() and
attr.getObject() = nodeTo.getPreUpdateNode().(CfgNode).getNode()
predicate attributeStoreStep(Node nodeFrom, AttributeContent c, PostUpdateNode nodeTo) {
exists(AttrWrite write |
write.accesses(nodeTo.getPreUpdateNode(), c.getAttribute()) and
nodeFrom = write.getValue()
)
}
@@ -1923,21 +1927,16 @@ pragma[noinline]
TupleElementContent small_tuple() { result.getIndex() <= 7 }
/**
* Holds if `nodeTo` is a read of an attribute (corresponding to `c`) of the object in `nodeFrom`.
* Holds if `nodeTo` is a read of the attribute `c` of the object `nodeFrom`.
*
* For example, in
* For example
* ```python
* obj.foo
* ```
* data flows from `obj` to `obj.foo` via a read from `foo`.
* is a read of the attribute `foo` from the object `obj`.
*/
predicate attributeReadStep(CfgNode nodeFrom, AttributeContent c, CfgNode nodeTo) {
exists(AttrNode attr |
nodeFrom.asCfgNode() = attr.getObject() and
nodeTo.asCfgNode() = attr and
attr.getName() = c.getAttribute() and
attr.isLoad()
)
predicate attributeReadStep(Node nodeFrom, AttributeContent c, AttrRead nodeTo) {
nodeTo.accesses(nodeFrom, c.getAttribute())
}
/**
@@ -1973,6 +1972,18 @@ predicate clearsContent(Node n, Content c) {
kwOverflowClearStep(n, c)
or
matchClearStep(n, c)
or
attributeClearStep(n, c)
}
/**
* Holds if values stored inside attribute `c` are cleared at node `n`.
*
* In `obj.foo = x` any old value stored in `foo` is cleared at the pre-update node
* associated with `obj`
*/
predicate attributeClearStep(Node n, AttributeContent c) {
exists(PostUpdateNode post | post.getPreUpdateNode() = n | attributeStoreStep(_, c, post))
}
//--------

View File

@@ -9,6 +9,7 @@
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate
/**
* INTERNAL: Do not use.
@@ -66,7 +67,12 @@ string prettyNodeForInlineTest(DataFlow::Node node) {
result = "[post]" + prettyExpr(e)
)
or
exists(Expr e | e = node.(DataFlowPrivate::SyntheticPreUpdateNode).getPostUpdateNode().asExpr() |
result = "[pre]" + prettyExpr(e)
)
or
not exists(node.asExpr()) and
not exists(node.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr()) and
not exists(node.(DataFlowPrivate::SyntheticPreUpdateNode).getPostUpdateNode().asExpr()) and
result = node.toString()
}

View File

@@ -167,8 +167,25 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
*/
predicate containerStep(DataFlow::CfgNode nodeFrom, DataFlow::Node nodeTo) {
// construction by literal
// TODO: Not limiting the content argument here feels like a BIG hack, but we currently get nothing for free :|
DataFlowPrivate::storeStep(nodeFrom, _, nodeTo)
//
// TODO: once we have proper flow-summary modeling, we might not need this step any
// longer -- but there needs to be a matching read-step for the store-step, and we
// don't provide that right now.
DataFlowPrivate::listStoreStep(nodeFrom, _, nodeTo)
or
DataFlowPrivate::setStoreStep(nodeFrom, _, nodeTo)
or
DataFlowPrivate::tupleStoreStep(nodeFrom, _, nodeTo)
or
DataFlowPrivate::dictStoreStep(nodeFrom, _, nodeTo)
or
// comprehension, so there is taint-flow from `x` in `[x for x in xs]` to the
// resulting list of the list-comprehension.
//
// TODO: once we have proper flow-summary modeling, we might not need this step any
// longer -- but there needs to be a matching read-step for the store-step, and we
// don't provide that right now.
DataFlowPrivate::comprehensionStoreStep(nodeFrom, _, nodeTo)
or
// constructor call
exists(DataFlow::CallCfgNode call | call = nodeTo |

View File

@@ -2295,4 +2295,22 @@ module PrivateDjango {
override string getMimetypeDefault() { none() }
}
// ---------------------------------------------------------------------------
// Logging
// ---------------------------------------------------------------------------
/**
* A standard Python logger instance from Django.
* see https://github.com/django/django/blob/stable/4.0.x/django/utils/log.py#L11
*/
private class DjangoLogger extends Stdlib::Logger::InstanceSource {
DjangoLogger() {
this =
API::moduleImport("django")
.getMember("utils")
.getMember("log")
.getMember("request_logger")
.getAnImmediateUse()
}
}
}

View File

@@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.Concepts
private import semmle.python.frameworks.Werkzeug
private import semmle.python.frameworks.Stdlib
private import semmle.python.ApiGraphs
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
private import semmle.python.security.dataflow.PathInjectionCustomizations
@@ -569,4 +570,18 @@ module Flask {
result in [this.getArg(0), this.getArgByName("filename_or_fp")]
}
}
// ---------------------------------------------------------------------------
// Logging
// ---------------------------------------------------------------------------
/**
* A Flask application provides a standard Python logger via the `logger` attribute.
*
* See
* - https://flask.palletsprojects.com/en/2.0.x/api/#flask.Flask.logger
* - https://flask.palletsprojects.com/en/2.0.x/logging/
*/
private class FlaskLogger extends Stdlib::Logger::InstanceSource {
FlaskLogger() { this = FlaskApp::instance().getMember("logger").getAnImmediateUse() }
}
}

View File

@@ -0,0 +1,75 @@
/**
* Provides classes modeling security-relevant aspects of the `python-ldap` PyPI package (imported as `ldap`).
* See https://www.python-ldap.org/en/python-ldap-3.3.0/index.html
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
* Provides models for the `python-ldap` PyPI package (imported as `ldap`).
*
* See https://www.python-ldap.org/en/python-ldap-3.3.0/index.html
*/
private module Ldap {
/**
* The execution of an `ldap` query.
*
* See https://www.python-ldap.org/en/python-ldap-3.3.0/reference/ldap.html#functions
*/
private class LdapQueryExecution extends DataFlow::CallCfgNode, LDAP::LdapExecution::Range {
LdapQueryExecution() {
this =
API::moduleImport("ldap")
.getMember("initialize")
.getReturn()
.getMember(["search", "search_s", "search_st", "search_ext", "search_ext_s"])
.getACall()
}
override DataFlow::Node getFilter() {
result in [this.getArg(2), this.getArgByName("filterstr")]
}
override DataFlow::Node getBaseDn() { result in [this.getArg(0), this.getArgByName("base")] }
}
/**
* A call to `ldap.dn.escape_dn_chars`.
*
* See https://github.com/python-ldap/python-ldap/blob/7ce471e238cdd9a4dd8d17baccd1c9e05e6f894a/Lib/ldap/dn.py#L17
*/
private class LdapEscapeDnCall extends DataFlow::CallCfgNode, Escaping::Range {
LdapEscapeDnCall() {
this = API::moduleImport("ldap").getMember("dn").getMember("escape_dn_chars").getACall()
}
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("s")] }
override DataFlow::Node getOutput() { result = this }
override string getKind() { result = Escaping::getLdapDnKind() }
}
/**
* A call to `ldap.filter.escape_filter_chars`.
*
* See https://www.python-ldap.org/en/python-ldap-3.3.0/reference/ldap-filter.html#ldap.filter.escape_filter_chars
*/
private class LdapEscapeFilterCall extends DataFlow::CallCfgNode, Escaping::Range {
LdapEscapeFilterCall() {
this =
API::moduleImport("ldap").getMember("filter").getMember("escape_filter_chars").getACall()
}
override DataFlow::Node getAnInput() {
result in [this.getArg(0), this.getArgByName("assertion_value")]
}
override DataFlow::Node getOutput() { result = this }
override string getKind() { result = Escaping::getLdapFilterKind() }
}
}

View File

@@ -0,0 +1,80 @@
/**
* Provides classes modeling security-relevant aspects of the `ldap3` PyPI package
* See https://pypi.org/project/ldap3/
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
/**
* Provides models for the `ldap3` PyPI package
*
* See https://pypi.org/project/ldap3/
*/
private module Ldap3 {
/** The execution of an `ldap` query. */
private class LdapQueryExecution extends DataFlow::CallCfgNode, LDAP::LdapExecution::Range {
LdapQueryExecution() {
this =
API::moduleImport("ldap3")
.getMember("Connection")
.getReturn()
.getMember("search")
.getACall()
}
override DataFlow::Node getFilter() {
result in [this.getArg(1), this.getArgByName("search_filter")]
}
override DataFlow::Node getBaseDn() {
result in [this.getArg(0), this.getArgByName("search_base")]
}
}
/**
* A call to `ldap3.utils.dn.escape_rdn`.
*
* See https://github.com/cannatag/ldap3/blob/4d33166f0869b929f59c6e6825a1b9505eb99967/ldap3/utils/dn.py#L390
*/
private class LdapEscapeDnCall extends DataFlow::CallCfgNode, Escaping::Range {
LdapEscapeDnCall() {
this =
API::moduleImport("ldap3")
.getMember("utils")
.getMember("dn")
.getMember("escape_rdn")
.getACall()
}
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("rdn")] }
override DataFlow::Node getOutput() { result = this }
override string getKind() { result = Escaping::getLdapDnKind() }
}
/**
* A call to `ldap3.utils.conv.escape_filter_chars`.
*
* See https://github.com/cannatag/ldap3/blob/4d33166f0869b929f59c6e6825a1b9505eb99967/ldap3/utils/conv.py#L91
*/
private class LdapEscapeFilterCall extends DataFlow::CallCfgNode, Escaping::Range {
LdapEscapeFilterCall() {
this =
API::moduleImport("ldap3")
.getMember("utils")
.getMember("conv")
.getMember("escape_filter_chars")
.getACall()
}
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("text")] }
override DataFlow::Node getOutput() { result = this }
override string getKind() { result = Escaping::getLdapFilterKind() }
}
}

View File

@@ -237,6 +237,54 @@ module Stdlib {
}
}
}
// ---------------------------------------------------------------------------
// logging
// ---------------------------------------------------------------------------
/**
* Provides models for the `logging.Logger` class and subclasses.
*
* See https://docs.python.org/3.9/library/logging.html#logging.Logger.
*/
module Logger {
/** Gets a reference to the `logging.Logger` class or any subclass. */
private API::Node subclassRef() {
result = API::moduleImport("logging").getMember("Logger").getASubclass*()
}
/**
* A source of instances of `logging.Logger`, 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 the predicate `Logger::instance()` to get references to instances of `logging.Logger`.
*/
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
/** A direct instantiation of `logging.Logger`. */
private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode {
ClassInstantiation() {
this = subclassRef().getACall()
or
this = API::moduleImport("logging").getMember("root").getAnImmediateUse()
or
this = API::moduleImport("logging").getMember("getLogger").getACall()
}
}
/** Gets a reference to an instance of `logging.Logger`. */
private DataFlow::TypeTrackingNode 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 `logging.Logger`. */
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
}
}
/**
@@ -2642,27 +2690,6 @@ private module StdlibPrivate {
// ---------------------------------------------------------------------------
// logging
// ---------------------------------------------------------------------------
/**
* Provides models for the `logging.Logger` class and subclasses.
*
* See https://docs.python.org/3.9/library/logging.html#logging.Logger.
*/
module Logger {
/** Gets a reference to the `logging.Logger` class or any subclass. */
API::Node subclassRef() {
result = API::moduleImport("logging").getMember("Logger").getASubclass*()
}
/** Gets a reference to an instance of `logging.Logger` or any subclass. */
API::Node instance() {
result = subclassRef().getReturn()
or
result = API::moduleImport("logging").getMember("root")
or
result = API::moduleImport("logging").getMember("getLogger").getReturn()
}
}
/**
* A call to one of the logging methods from `logging` or on a `logging.Logger`
* subclass.
@@ -2683,14 +2710,14 @@ private module StdlibPrivate {
method = "log" and
msgIndex = 1
|
this = Logger::instance().getMember(method).getACall()
this.(DataFlow::MethodCallNode).calls(Stdlib::Logger::instance(), method)
or
this = API::moduleImport("logging").getMember(method).getACall()
)
}
override DataFlow::Node getAnInput() {
result = this.getArgByName("msg")
result = this.getArgByName(["msg", "extra"])
or
result = this.getArg(any(int i | i >= msgIndex))
}

View File

@@ -114,49 +114,33 @@ class ClassList extends TClassList {
this = Empty() and result = Empty()
}
predicate legalMergeHead(ClassObjectInternal cls) {
this.getTail().doesNotContain(cls)
or
this = Empty()
}
predicate contains(ClassObjectInternal cls) {
cls = this.getHead()
or
this.getTail().contains(cls)
}
/** Use negative formulation to avoid negative recursion */
predicate doesNotContain(ClassObjectInternal cls) {
this.relevantForContains(cls) and
cls != this.getHead() and
this.getTail().doesNotContain(cls)
or
this = Empty()
}
private predicate relevantForContains(ClassObjectInternal cls) {
exists(ClassListList list |
list.getItem(_).getHead() = cls and
list.getItem(_) = this
)
or
exists(ClassList l |
l.relevantForContains(cls) and
this = l.getTail()
)
}
pragma[nomagic]
ClassObjectInternal findDeclaringClass(string name) {
exists(ClassDecl head | head = this.getHead().getClassDeclaration() |
if head.declaresAttribute(name)
then result = this.getHead()
else result = this.getTail().findDeclaringClass(name)
exists(ClassObjectInternal head, ClassList tail, ClassDecl decl |
this = Cons(head, tail) and decl = head.getClassDeclaration()
|
if decl.declaresAttribute(name) then result = head else result = tail.findDeclaringClass(name)
)
}
pragma[noinline]
private ClassObjectInternal findDeclaringClassAttribute(string name) {
result = this.findDeclaringClass(name) and
(
exists(any(Builtin b).getMember(name))
or
declaredAttributeVar(_, name, _)
)
}
predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
exists(ClassObjectInternal decl | decl = this.findDeclaringClass(name) |
exists(ClassObjectInternal decl | decl = this.findDeclaringClassAttribute(name) |
Types::declaredAttribute(decl, name, value, origin)
)
}
@@ -199,12 +183,18 @@ class ClassList extends TClassList {
or
this.duplicate(n) and result = this.deduplicate(n + 1)
or
exists(ClassObjectInternal cls |
n = this.firstIndex(cls) and
result = Cons(cls, this.deduplicate(n + 1))
exists(ClassObjectInternal cls, ClassList tail |
this.deduplicateCons(n, cls, tail) and
result = Cons(cls, tail)
)
}
pragma[nomagic]
private predicate deduplicateCons(int n, ClassObjectInternal cls, ClassList tail) {
n = this.firstIndex(cls) and
tail = this.deduplicate(n + 1)
}
predicate isEmpty() { this = Empty() }
ClassList reverse() { reverse_step(this, Empty(), result) }
@@ -273,6 +263,24 @@ private class ClassListList extends TClassListList {
result = this.getTail().getItem(n - 1)
}
/**
* Same as
*
* ```ql
* result = this.getItem(n) and n = this.length() - 1
* ```
*
* but avoids non-linear recursion.
*/
ClassList getLastItem(int n) {
n = 0 and this = ConsList(result, EmptyList())
or
exists(ClassListList tail |
this = ConsList(_, tail) and
result = tail.getLastItem(n - 1)
)
}
private ClassObjectInternal getAHead() {
result = this.getHead().getHead()
or
@@ -295,17 +303,26 @@ private class ClassListList extends TClassListList {
ClassObjectInternal cls, ClassList removed_head, ClassListList removed_tail, int n
) {
cls = this.bestMergeCandidate() and
n = this.length() - 1 and
removed_head = this.getItem(n).removeHead(cls) and
removed_head = this.getLastItem(n).removeHead(cls) and
removed_tail = EmptyList()
or
removed_head = this.removedClassPartsCons1(cls, removed_tail, n).removeHead(cls)
}
pragma[nomagic]
predicate removedClassPartsCons0(ClassObjectInternal cls, ClassListList removed_tail, int n) {
exists(ClassList prev_head, ClassListList prev_tail |
this.removedClassParts(cls, prev_head, prev_tail, n + 1) and
removed_head = this.getItem(n).removeHead(cls) and
removed_tail = ConsList(prev_head, prev_tail)
)
}
pragma[nomagic]
ClassList removedClassPartsCons1(ClassObjectInternal cls, ClassListList removed_tail, int n) {
this.removedClassPartsCons0(cls, removed_tail, n) and
result = this.getItem(n)
}
ClassListList remove(ClassObjectInternal cls) {
exists(ClassList removed_head, ClassListList removed_tail |
this.removedClassParts(cls, removed_head, removed_tail, 0) and
@@ -315,18 +332,34 @@ private class ClassListList extends TClassListList {
this = EmptyList() and result = EmptyList()
}
predicate legalMergeCandidate(ClassObjectInternal cls, int n) {
cls = this.getAHead() and n = this.length()
pragma[nomagic]
private predicate legalMergeCandidateNonEmpty(
ClassObjectInternal cls, ClassListList remainingList, ClassList remaining
) {
this.legalMergeCandidate(cls, ConsList(Cons(_, remaining), remainingList))
or
this.getItem(n).legalMergeHead(cls) and
this.legalMergeCandidate(cls, n + 1)
exists(ClassObjectInternal head |
this.legalMergeCandidateNonEmpty(cls, remainingList, Cons(head, remaining)) and
cls != head
)
}
predicate legalMergeCandidate(ClassObjectInternal cls) { this.legalMergeCandidate(cls, 0) }
private predicate legalMergeCandidate(ClassObjectInternal cls, ClassListList remaining) {
cls = this.getAHead() and remaining = this
or
this.legalMergeCandidate(cls, ConsList(Empty(), remaining))
or
this.legalMergeCandidateNonEmpty(cls, remaining, Empty())
}
pragma[noinline]
predicate legalMergeCandidate(ClassObjectInternal cls) {
this.legalMergeCandidate(cls, EmptyList())
}
pragma[noinline]
predicate illegalMergeCandidate(ClassObjectInternal cls) {
cls = this.getAHead() and
this.getItem(_).getTail().contains(cls)
this.legalMergeCandidateNonEmpty(cls, _, Cons(cls, _))
}
ClassObjectInternal bestMergeCandidate(int n) {
@@ -337,6 +370,7 @@ private class ClassListList extends TClassListList {
)
}
pragma[noinline]
ClassObjectInternal bestMergeCandidate() { result = this.bestMergeCandidate(0) }
/**
@@ -417,16 +451,27 @@ private predicate merge_step(
remaining_list = original
or
/* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */
exists(ClassObjectInternal head, ClassList prev_reverse_mro, ClassListList prev_list |
merge_step(prev_reverse_mro, prev_list, original) and
head = prev_list.bestMergeCandidate() and
reversed_mro = Cons(head, prev_reverse_mro) and
remaining_list = prev_list.remove(head)
exists(ClassObjectInternal head, ClassList prev_reverse_mro |
merge_stepCons(head, prev_reverse_mro, remaining_list, original) and
reversed_mro = Cons(head, prev_reverse_mro)
)
or
merge_step(reversed_mro, ConsList(Empty(), remaining_list), original)
}
pragma[nomagic]
private predicate merge_stepCons(
ClassObjectInternal head, ClassList prev_reverse_mro, ClassListList remaining_list,
ClassListList original
) {
/* Removes the best merge candidate from `remaining_list` and prepends it to `reversed_mro` */
exists(ClassListList prev_list |
merge_step(prev_reverse_mro, prev_list, original) and
head = prev_list.bestMergeCandidate() and
remaining_list = prev_list.remove(head)
)
}
/* Helpers for `ClassList.reverse()` */
private predicate needs_reversing(ClassList lst) {
merge_step(lst, EmptyList(), _)
@@ -439,10 +484,17 @@ private predicate reverse_step(ClassList lst, ClassList remainder, ClassList rev
or
exists(ClassObjectInternal head, ClassList tail |
reversed = Cons(head, tail) and
reverse_step(lst, Cons(head, remainder), tail)
reverse_stepCons(lst, remainder, head, tail)
)
}
pragma[nomagic]
private predicate reverse_stepCons(
ClassList lst, ClassList remainder, ClassObjectInternal head, ClassList tail
) {
reverse_step(lst, Cons(head, remainder), tail)
}
module Mro {
cached
ClassList newStyleMro(ClassObjectInternal cls) {

View File

@@ -1429,20 +1429,51 @@ module Expressions {
}
pragma[noinline]
predicate subscriptPointsTo(
private predicate indexPointsToInt(ControlFlowNode index, PointsToContext context, int n) {
index = any(SubscriptNode subscr).getIndex() and
PointsToInternal::pointsTo(index, context, TInt(n), _)
}
pragma[noinline]
private predicate getItemSequenceObjectInternal(
ObjectInternal value, SequenceObjectInternal objvalue, int n
) {
value = objvalue.getItem(n)
}
pragma[noinline]
private predicate subscriptObjectAndIndexPointsToInt(
SubscriptNode subscr, PointsToContext context, ControlFlowNode obj, ObjectInternal objvalue,
int n
) {
exists(ControlFlowNode index |
subscriptObjectAndIndex(subscr, context, obj, objvalue, index) and
indexPointsToInt(index, context, n)
)
}
deprecated predicate subscriptPointsTo(
SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode obj, ObjectInternal objvalue
) {
subscriptPointsTo(subscr, context, value, obj, objvalue) and
origin = subscr
}
pragma[noinline]
private predicate subscriptPointsTo(
SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode obj,
ObjectInternal objvalue
) {
exists(ControlFlowNode index | subscriptObjectAndIndex(subscr, context, obj, objvalue, index) |
objvalue.subscriptUnknown() and
value = ObjectInternal::unknown()
or
exists(int n |
PointsToInternal::pointsTo(index, context, TInt(n), _) and
value = objvalue.(SequenceObjectInternal).getItem(n)
)
) and
origin = subscr
)
or
exists(int n |
subscriptObjectAndIndexPointsToInt(subscr, context, obj, objvalue, n) and
getItemSequenceObjectInternal(value, objvalue, n)
)
}
predicate subscriptPartsPointsTo(
@@ -1466,15 +1497,22 @@ module Expressions {
index = subscr.getIndex()
}
deprecated predicate binaryPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
binaryPointsTo(b, context, value, operand, opvalue) and
origin = b
}
/**
* Tracking too many binary expressions is likely to kill performance, so just say anything other than addition or bitwise or is 'unknown'.
*/
pragma[noinline]
predicate binaryPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
private predicate binaryPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
ObjectInternal opvalue
) {
origin = b and
operand = genericBinaryOperand(b) and
PointsToInternal::pointsTo(operand, context, opvalue, _) and
value = ObjectInternal::unknown()
@@ -1491,12 +1529,19 @@ module Expressions {
)
}
pragma[noinline]
predicate addPointsTo(
deprecated predicate addPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
origin = b and
addPointsTo(b, context, value, operand, opvalue) and
origin = b
}
pragma[noinline]
private predicate addPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
ObjectInternal opvalue
) {
exists(Operator op |
b.operands(operand, op, _)
or
@@ -1508,12 +1553,19 @@ module Expressions {
)
}
pragma[noinline]
predicate bitOrPointsTo(
deprecated predicate bitOrPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
origin = b and
bitOrPointsTo(b, context, value, operand, opvalue) and
origin = b
}
pragma[noinline]
private predicate bitOrPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
ObjectInternal opvalue
) {
exists(Operator op, ControlFlowNode other |
b.operands(operand, op, other)
or
@@ -1533,10 +1585,18 @@ module Expressions {
value = obj.intValue()
}
pragma[noinline]
predicate unaryPointsTo(
deprecated predicate unaryPointsTo(
UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
unaryPointsTo(u, context, value, operand, opvalue) and
origin = u
}
pragma[noinline]
private predicate unaryPointsTo(
UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
ObjectInternal opvalue
) {
exists(Unaryop op |
op = u.getNode().getOp() and
@@ -1548,14 +1608,21 @@ module Expressions {
op instanceof USub and value = ObjectInternal::fromInt(-opvalue.intValue())
or
not op instanceof Not and opvalue = ObjectInternal::unknown() and value = opvalue
) and
origin = u
)
}
deprecated predicate builtinCallPointsTo(
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode arg, ObjectInternal argvalue
) {
builtinCallPointsTo(call, context, value, arg, argvalue) and
origin = call
}
pragma[noinline]
predicate builtinCallPointsTo(
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode arg, ObjectInternal argvalue
private predicate builtinCallPointsTo(
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode arg,
ObjectInternal argvalue
) {
PointsToInternal::pointsTo(arg, context, argvalue, _) and
arg = call.getArg(0) and
@@ -1569,8 +1636,7 @@ module Expressions {
callable != ObjectInternal::builtin("hasattr") and
callable.isClass() = false and
value = ObjectInternal::unknown()
) and
origin = call
)
}
pragma[noinline]
@@ -1585,11 +1651,10 @@ module Expressions {
pragma[noinline]
private predicate lenCallPointsTo(
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode arg, ObjectInternal argvalue
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode arg,
ObjectInternal argvalue
) {
len_call(call, arg, context, argvalue) and
origin = call and
exists(int len | len = argvalue.length() |
value = TInt(len) and len >= 0
or
@@ -1815,19 +1880,26 @@ module Expressions {
) {
attributePointsTo(expr, context, value, origin, subexpr, subvalue)
or
subscriptPointsTo(expr, context, value, origin, subexpr, subvalue)
subscriptPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
addPointsTo(expr, context, value, origin, subexpr, subvalue)
addPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
bitOrPointsTo(expr, context, value, origin, subexpr, subvalue)
bitOrPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
binaryPointsTo(expr, context, value, origin, subexpr, subvalue)
binaryPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
unaryPointsTo(expr, context, value, origin, subexpr, subvalue)
unaryPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
builtinCallPointsTo(expr, context, value, origin, subexpr, subvalue)
builtinCallPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
lenCallPointsTo(expr, context, value, origin, subexpr, subvalue)
lenCallPointsTo(expr, context, value, subexpr, subvalue) and
origin = expr
or
typeCallPointsTo(expr, context, value, origin, subexpr, subvalue)
or
@@ -2068,6 +2140,12 @@ module Conditionals {
}
}
/** INTERNAL: Do not use. */
predicate declaredAttributeVar(PythonClassObjectInternal cls, string name, EssaVariable var) {
name = var.getName() and
var.getAUse() = cls.getScope().getANormalExit()
}
cached
module Types {
cached
@@ -2163,8 +2241,7 @@ module Types {
or
value != ObjectInternal::undefined() and
exists(EssaVariable var |
name = var.getName() and
var.getAUse() = cls.(PythonClassObjectInternal).getScope().getANormalExit() and
declaredAttributeVar(cls, name, var) and
PointsToInternal::variablePointsTo(var, _, value, origin)
)
}

View File

@@ -427,6 +427,7 @@ abstract class RegexString extends Expr {
}
predicate normalCharacter(int start, int end) {
end = start + 1 and
this.character(start, end) and
not this.specialCharacter(start, end, _)
}
@@ -446,6 +447,49 @@ abstract class RegexString extends Expr {
)
}
/**
* Holds if the range [start:end) consists of only 'normal' characters.
*/
predicate normalCharacterSequence(int start, int end) {
// a normal character inside a character set is interpreted on its own
this.normalCharacter(start, end) and
this.inCharSet(start)
or
// a maximal run of normal characters is considered as one constant
exists(int s, int e |
e = max(int i | this.normalCharacterRun(s, i)) and
not this.inCharSet(s)
|
// 'abc' can be considered one constant, but
// 'abc+' has to be broken up into 'ab' and 'c+',
// as the qualifier only applies to 'c'.
if this.qualifier(e, _, _, _)
then
end = e and start = e - 1
or
end = e - 1 and start = s and start < end
else (
end = e and
start = s
)
)
}
private predicate normalCharacterRun(int start, int end) {
(
this.normalCharacterRun(start, end - 1)
or
start = end - 1 and not this.normalCharacter(start - 1, start)
) and
this.normalCharacter(end - 1, end)
}
private predicate characterItem(int start, int end) {
this.normalCharacterSequence(start, end) or
this.escapedCharacter(start, end) or
this.specialCharacter(start, end, _)
}
/** Whether the text in the range start,end is a group */
predicate group(int start, int end) {
this.groupContents(start, end, _, _)
@@ -717,7 +761,7 @@ abstract class RegexString extends Expr {
string getBackrefName(int start, int end) { this.named_backreference(start, end, result) }
private predicate baseItem(int start, int end) {
this.character(start, end) and
this.characterItem(start, end) and
not exists(int x, int y | this.charSet(x, y) and x <= start and y >= end)
or
this.group(start, end)
@@ -837,14 +881,14 @@ abstract class RegexString extends Expr {
}
private predicate item_start(int start) {
this.character(start, _) or
this.characterItem(start, _) or
this.isGroupStart(start) or
this.charSet(start, _) or
this.backreference(start, _)
}
private predicate item_end(int end) {
this.character(_, end)
this.characterItem(_, end)
or
exists(int endm1 | this.isGroupEnd(endm1) and end = endm1 + 1)
or
@@ -953,7 +997,7 @@ abstract class RegexString extends Expr {
*/
predicate firstItem(int start, int end) {
(
this.character(start, end)
this.characterItem(start, end)
or
this.qualifiedItem(start, end, _, _)
or
@@ -968,7 +1012,7 @@ abstract class RegexString extends Expr {
*/
predicate lastItem(int start, int end) {
(
this.character(start, end)
this.characterItem(start, end)
or
this.qualifiedItem(start, end, _, _)
or

View File

@@ -4,7 +4,7 @@ import semmle.python.security.SensitiveData
import semmle.python.dataflow.Files
import semmle.python.web.Http
module ClearTextStorage {
deprecated module ClearTextStorage {
abstract class Sink extends TaintSink {
override predicate sinks(TaintKind kind) { kind instanceof SensitiveData }
}
@@ -26,7 +26,7 @@ module ClearTextStorage {
}
}
module ClearTextLogging {
deprecated module ClearTextLogging {
abstract class Sink extends TaintSink {
override predicate sinks(TaintKind kind) { kind instanceof SensitiveData }
}

View File

@@ -3,12 +3,12 @@ import semmle.python.dataflow.TaintTracking
private import semmle.python.security.SensitiveData
private import semmle.crypto.Crypto as CryptoLib
abstract class WeakCryptoSink extends TaintSink {
abstract deprecated class WeakCryptoSink extends TaintSink {
override predicate sinks(TaintKind taint) { taint instanceof SensitiveData }
}
/** Modeling the 'pycrypto' package https://github.com/dlitz/pycrypto (latest release 2013) */
module Pycrypto {
deprecated module Pycrypto {
ModuleValue cipher(string name) { result = Module::named("Crypto.Cipher").attr(name) }
class CipherInstance extends TaintKind {
@@ -58,7 +58,7 @@ module Pycrypto {
}
}
module Cryptography {
deprecated module Cryptography {
ModuleValue ciphers() {
result = Module::named("cryptography.hazmat.primitives.ciphers") and
result.isPackage()
@@ -128,7 +128,7 @@ module Cryptography {
}
}
private class CipherConfig extends TaintTracking::Configuration {
deprecated private class CipherConfig extends TaintTracking::Configuration {
CipherConfig() { this = "Crypto cipher config" }
override predicate isSource(TaintTracking::Source source) {

View File

@@ -7,13 +7,15 @@ import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
private Value traceback_function(string name) { result = Module::named("traceback").attr(name) }
deprecated private Value traceback_function(string name) {
result = Module::named("traceback").attr(name)
}
/**
* This represents information relating to an exception, for instance the
* message, arguments or parts of the exception traceback.
*/
class ExceptionInfo extends StringKind {
deprecated class ExceptionInfo extends StringKind {
ExceptionInfo() { this = "exception.info" }
override string repr() { result = "exception info" }
@@ -23,12 +25,12 @@ class ExceptionInfo extends StringKind {
* A class representing sources of information about
* execution state exposed in tracebacks and the like.
*/
abstract class ErrorInfoSource extends TaintSource { }
abstract deprecated class ErrorInfoSource extends TaintSource { }
/**
* This kind represents exceptions themselves.
*/
class ExceptionKind extends TaintKind {
deprecated class ExceptionKind extends TaintKind {
ExceptionKind() { this = "exception.kind" }
override string repr() { result = "exception" }
@@ -44,7 +46,7 @@ class ExceptionKind extends TaintKind {
* A source of exception objects, either explicitly created, or captured by an
* `except` statement.
*/
class ExceptionSource extends ErrorInfoSource {
deprecated class ExceptionSource extends ErrorInfoSource {
ExceptionSource() {
exists(ClassValue cls |
cls.getASuperType() = ClassValue::baseException() and
@@ -63,7 +65,7 @@ class ExceptionSource extends ErrorInfoSource {
* Represents a sequence of pieces of information relating to an exception,
* for instance the contents of the `args` attribute, or the stack trace.
*/
class ExceptionInfoSequence extends SequenceKind {
deprecated class ExceptionInfoSequence extends SequenceKind {
ExceptionInfoSequence() { this.getItem() instanceof ExceptionInfo }
}
@@ -71,7 +73,7 @@ class ExceptionInfoSequence extends SequenceKind {
* Represents calls to functions in the `traceback` module that return
* sequences of exception information.
*/
class CallToTracebackFunction extends ErrorInfoSource {
deprecated class CallToTracebackFunction extends ErrorInfoSource {
CallToTracebackFunction() {
exists(string name |
name in [
@@ -92,7 +94,7 @@ class CallToTracebackFunction extends ErrorInfoSource {
* Represents calls to functions in the `traceback` module that return a single
* string of information about an exception.
*/
class FormattedTracebackSource extends ErrorInfoSource {
deprecated class FormattedTracebackSource extends ErrorInfoSource {
FormattedTracebackSource() { this = traceback_function("format_exc").getACall() }
override string toString() { result = "exception.info.source" }

View File

@@ -1,6 +1,6 @@
import semmle.python.dataflow.Implementation
module TaintTrackingPaths {
deprecated module TaintTrackingPaths {
predicate edge(TaintTrackingNode src, TaintTrackingNode dest, string label) {
exists(TaintTrackingNode source, TaintTrackingNode sink |
source.getConfiguration().hasFlowPath(source, sink) and
@@ -11,6 +11,6 @@ module TaintTrackingPaths {
}
}
query predicate edges(TaintTrackingNode fromnode, TaintTrackingNode tonode) {
deprecated query predicate edges(TaintTrackingNode fromnode, TaintTrackingNode tonode) {
TaintTrackingPaths::edge(fromnode, tonode, _)
}

View File

@@ -15,7 +15,7 @@ import semmle.python.web.HttpRequest
import semmle.python.security.internal.SensitiveDataHeuristics
private import HeuristicNames
abstract class SensitiveData extends TaintKind {
abstract deprecated class SensitiveData extends TaintKind {
bindingset[this]
SensitiveData() { this = this }
@@ -23,7 +23,7 @@ abstract class SensitiveData extends TaintKind {
abstract SensitiveDataClassification getClassification();
}
module SensitiveData {
deprecated module SensitiveData {
class Secret extends SensitiveData {
Secret() { this = "sensitive.data.secret" }
@@ -115,4 +115,4 @@ module SensitiveData {
}
//Backwards compatibility
class SensitiveDataSource = SensitiveData::Source;
deprecated class SensitiveDataSource = SensitiveData::Source;

View File

@@ -0,0 +1,60 @@
/**
* Provides taint-tracking configurations for detecting LDAP injection vulnerabilities
*
* Note, for performance reasons: only import this file if
* `LdapInjection::Configuration` is needed, otherwise
* `LdapInjectionCustomizations` should be imported instead.
*/
import python
import semmle.python.Concepts
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.RemoteFlowSources
/**
* Provides aint-tracking configurations for detecting LDAP injection vulnerabilities.class
*
* Two configurations are provided. One is for detecting LDAP injection
* via the distinguished name (DN). The other is for detecting LDAP injection
* via the filter. These require different escapings.
*/
module LdapInjection {
import LdapInjectionCustomizations::LdapInjection
/**
* A taint-tracking configuration for detecting LDAP injection vulnerabilities
* via the distinguished name (DN) parameter of an LDAP search.
*/
class DnConfiguration extends TaintTracking::Configuration {
DnConfiguration() { this = "LdapDnInjection" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof DnSink }
override predicate isSanitizer(DataFlow::Node node) { node instanceof DnSanitizer }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof DnSanitizerGuard
}
}
/**
* A taint-tracking configuration for detecting LDAP injection vulnerabilities
* via the filter parameter of an LDAP search.
*/
class FilterConfiguration extends TaintTracking::Configuration {
FilterConfiguration() { this = "LdapFilterInjection" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof FilterSink }
override predicate isSanitizer(DataFlow::Node node) { node instanceof FilterSanitizer }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof FilterSanitizerGuard
}
}
}

View File

@@ -0,0 +1,97 @@
/**
* Provides default sources, sinks and sanitizers for detecting
* "ldap injection"
* vulnerabilities, as well as extension points for adding your own.
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.Concepts
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.BarrierGuards
/**
* Provides default sources, sinks and sanitizers for detecting
* "ldap injection"
* vulnerabilities, as well as extension points for adding your own.
*/
module LdapInjection {
/**
* A data flow source for "ldap injection" vulnerabilities.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for "ldap injection" vulnerabilities.
*/
abstract class DnSink extends DataFlow::Node { }
/**
* A data flow sink for "ldap injection" vulnerabilities.
*/
abstract class FilterSink extends DataFlow::Node { }
/**
* A sanitizer for "ldap injection" vulnerabilities.
*/
abstract class DnSanitizer extends DataFlow::Node { }
/**
* A sanitizer for "ldap injection" vulnerabilities.
*/
abstract class FilterSanitizer extends DataFlow::Node { }
/**
* A sanitizer guard for "ldap injection" vulnerabilities.
*/
abstract class DnSanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A sanitizer guard for "ldap injection" vulnerabilities.
*/
abstract class FilterSanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A source of remote user input, considered as a flow source.
*/
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
/**
* A logging operation, considered as a flow sink.
*/
class LdapExecutionAsDnSink extends DnSink {
LdapExecutionAsDnSink() { this = any(LDAP::LdapExecution ldap).getBaseDn() }
}
/**
* A logging operation, considered as a flow sink.
*/
class LdapExecutionAsFilterSink extends FilterSink {
LdapExecutionAsFilterSink() { this = any(LDAP::LdapExecution ldap).getFilter() }
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
*/
class StringConstCompareAsDnSanitizerGuard extends DnSanitizerGuard, StringConstCompare { }
/**
* A comparison with a constant string, considered as a sanitizer-guard.
*/
class StringConstCompareAsFilterSanitizerGuard extends FilterSanitizerGuard, StringConstCompare {
}
/**
* A call to replace line breaks functions as a sanitizer.
*/
class LdapDnEscapingSanitizer extends DnSanitizer, DataFlow::CallCfgNode {
LdapDnEscapingSanitizer() { this = any(LdapDnEscaping ldapDnEsc).getOutput() }
}
/**
* A call to replace line breaks functions as a sanitizer.
*/
class LdapFilterEscapingSanitizer extends FilterSanitizer, DataFlow::CallCfgNode {
LdapFilterEscapingSanitizer() { this = any(LdapFilterEscaping ldapDnEsc).getOutput() }
}
}

View File

@@ -0,0 +1,35 @@
/**
* Provides a taint-tracking configuration for tracking untrusted user input used in log entries.
*
* Note, for performance reasons: only import this file if
* `LogInjection::Configuration` is needed, otherwise
* `LogInjectionCustomizations` should be imported instead.
*/
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/**
* Provides a taint-tracking configuration for tracking untrusted user input used in log entries.
*/
module LogInjection {
import LogInjectionCustomizations::LogInjection
/**
* A taint-tracking configuration for tracking untrusted user input used in log entries.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "LogInjection" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}
}

View File

@@ -0,0 +1,73 @@
/**
* Provides default sources, sinks and sanitizers for detecting
* "log injection"
* vulnerabilities, as well as extension points for adding your own.
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.Concepts
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.BarrierGuards
/**
* Provides default sources, sinks and sanitizers for detecting
* "log injection"
* vulnerabilities, as well as extension points for adding your own.
*/
module LogInjection {
/**
* A data flow source for "log injection" vulnerabilities.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for "log injection" vulnerabilities.
*/
abstract class Sink extends DataFlow::Node { }
/**
* A sanitizer for "log injection" vulnerabilities.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A sanitizer guard for "log injection" vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A source of remote user input, considered as a flow source.
*/
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
/**
* A logging operation, considered as a flow sink.
*/
class LoggingAsSink extends Sink {
LoggingAsSink() { this = any(Logging write).getAnInput() }
}
/**
* A comparison with a constant string, considered as a sanitizer-guard.
*/
class StringConstCompareAsSanitizerGuard extends SanitizerGuard, StringConstCompare { }
/**
* A call to replace line breaks, considered as a sanitizer.
*/
class ReplaceLineBreaksSanitizer extends Sanitizer, DataFlow::CallCfgNode {
// Note: This sanitizer is not 100% accurate, since:
// - we do not check that all kinds of line breaks are replaced
// - we do not check that one kind of line breaks is not replaced by another
//
// However, we lack a simple way to do better, and the query would likely
// be too noisy without this.
//
// TODO: Consider rewriting using flow states.
ReplaceLineBreaksSanitizer() {
this.getFunction().(DataFlow::AttrRead).getAttributeName() = "replace" and
this.getArg(0).asExpr().(StrConst).getText() in ["\r\n", "\n"]
}
}
}

View File

@@ -2,7 +2,7 @@ import python
import semmle.python.security.strings.Basic
/** Assume that taint flows from argument to result for *any* call */
class AnyCallStringFlow extends DataFlowExtension::DataFlowNode {
deprecated class AnyCallStringFlow extends DataFlowExtension::DataFlowNode {
AnyCallStringFlow() { any(CallNode call).getAnArg() = this }
override ControlFlowNode getASuccessorNode() { result.(CallNode).getAnArg() = this }

View File

@@ -11,18 +11,18 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
/** Abstract taint sink that is potentially vulnerable to malicious shell commands. */
abstract class CommandSink extends TaintSink { }
abstract deprecated class CommandSink extends TaintSink { }
private ModuleObject osOrPopenModule() { result.getName() = ["os", "popen2"] }
deprecated private ModuleObject osOrPopenModule() { result.getName() = ["os", "popen2"] }
private Object makeOsCall() {
deprecated private Object makeOsCall() {
exists(string name | result = ModuleObject::named("subprocess").attr(name) |
name = ["Popen", "call", "check_call", "check_output", "run"]
)
}
/**Special case for first element in sequence. */
class FirstElementKind extends TaintKind {
deprecated class FirstElementKind extends TaintKind {
FirstElementKind() { this = "sequence[" + any(ExternalStringKind key) + "][0]" }
override string repr() { result = "first item in sequence of " + this.getItem().repr() }
@@ -31,7 +31,7 @@ class FirstElementKind extends TaintKind {
ExternalStringKind getItem() { this = "sequence[" + result + "][0]" }
}
class FirstElementFlow extends DataFlowExtension::DataFlowNode {
deprecated class FirstElementFlow extends DataFlowExtension::DataFlowNode {
FirstElementFlow() { this = any(SequenceNode s).getElement(0) }
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
@@ -43,7 +43,7 @@ class FirstElementFlow extends DataFlowExtension::DataFlowNode {
* A taint sink that is potentially vulnerable to malicious shell commands.
* The `vuln` in `subprocess.call(shell=vuln)` and similar calls.
*/
class ShellCommand extends CommandSink {
deprecated class ShellCommand extends CommandSink {
override string toString() { result = "shell command" }
ShellCommand() {
@@ -81,7 +81,7 @@ class ShellCommand extends CommandSink {
* A taint sink that is potentially vulnerable to malicious shell commands.
* The `vuln` in `subprocess.call(vuln, ...)` and similar calls.
*/
class OsCommandFirstArgument extends CommandSink {
deprecated class OsCommandFirstArgument extends CommandSink {
override string toString() { result = "OS command first argument" }
OsCommandFirstArgument() {
@@ -111,7 +111,7 @@ class OsCommandFirstArgument extends CommandSink {
* A taint sink that is potentially vulnerable to malicious shell commands.
* The `vuln` in `invoke.run(vuln, ...)` and similar calls.
*/
class InvokeRun extends CommandSink {
deprecated class InvokeRun extends CommandSink {
InvokeRun() {
this = Value::named("invoke.run").(FunctionValue).getArgumentForCall(_, 0)
or
@@ -127,12 +127,12 @@ class InvokeRun extends CommandSink {
* Internal TaintKind to track the invoke.Context instance passed to functions
* marked with @invoke.task
*/
private class InvokeContextArg extends TaintKind {
deprecated private class InvokeContextArg extends TaintKind {
InvokeContextArg() { this = "InvokeContextArg" }
}
/** Internal TaintSource to track the context passed to functions marked with @invoke.task */
private class InvokeContextArgSource extends TaintSource {
deprecated private class InvokeContextArgSource extends TaintSource {
InvokeContextArgSource() {
exists(Function f, Expr decorator |
count(f.getADecorator()) = 1 and
@@ -158,7 +158,7 @@ private class InvokeContextArgSource extends TaintSource {
* A taint sink that is potentially vulnerable to malicious shell commands.
* The `vuln` in `invoke.Context().run(vuln, ...)` and similar calls.
*/
class InvokeContextRun extends CommandSink {
deprecated class InvokeContextRun extends CommandSink {
InvokeContextRun() {
exists(CallNode call |
any(InvokeContextArg k).taints(call.getFunction().(AttrNode).getObject("run"))
@@ -187,7 +187,7 @@ class InvokeContextRun extends CommandSink {
* A taint sink that is potentially vulnerable to malicious shell commands.
* The `vuln` in `fabric.Group().run(vuln, ...)` and similar calls.
*/
class FabricGroupRun extends CommandSink {
deprecated class FabricGroupRun extends CommandSink {
FabricGroupRun() {
exists(ClassValue cls |
cls.getASuperType() = Value::named("fabric.Group") and
@@ -203,7 +203,7 @@ class FabricGroupRun extends CommandSink {
// -------------------------------------------------------------------------- //
// Modeling of the 'invoke' package and 'fabric' package (v 1.x)
// -------------------------------------------------------------------------- //
class FabricV1Commands extends CommandSink {
deprecated class FabricV1Commands extends CommandSink {
FabricV1Commands() {
// since `run` and `sudo` are decorated, we can't use FunctionValue's :(
exists(CallNode call |
@@ -228,7 +228,7 @@ class FabricV1Commands extends CommandSink {
* An extension that propagates taint from the arguments of `fabric.api.execute(func, arg0, arg1, ...)`
* to the parameters of `func`, since this will call `func(arg0, arg1, ...)`.
*/
class FabricExecuteExtension extends DataFlowExtension::DataFlowNode {
deprecated class FabricExecuteExtension extends DataFlowExtension::DataFlowNode {
CallNode call;
FabricExecuteExtension() {

View File

@@ -2,7 +2,7 @@ import python
import semmle.python.dataflow.TaintTracking
/** `pickle.loads(untrusted)` vulnerability. */
abstract class DeserializationSink extends TaintSink {
abstract deprecated class DeserializationSink extends TaintSink {
bindingset[this]
DeserializationSink() { this = this }
}

View File

@@ -14,7 +14,7 @@ import semmle.python.security.strings.Untrusted
* A taint sink that represents an argument to exec or eval that is vulnerable to malicious input.
* The `vuln` in `exec(vuln)` or similar.
*/
class StringEvaluationNode extends TaintSink {
deprecated class StringEvaluationNode extends TaintSink {
override string toString() { result = "exec or eval" }
StringEvaluationNode() {

View File

@@ -11,13 +11,15 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.security.injection.Deserialization
private FunctionObject marshalLoads() { result = ModuleObject::named("marshal").attr("loads") }
deprecated private FunctionObject marshalLoads() {
result = ModuleObject::named("marshal").attr("loads")
}
/**
* A taint sink that is potentially vulnerable to malicious marshaled objects.
* The `vuln` in `marshal.loads(vuln)`.
*/
class UnmarshalingNode extends DeserializationSink {
deprecated class UnmarshalingNode extends DeserializationSink {
override string toString() { result = "unmarshaling vulnerability" }
UnmarshalingNode() {

View File

@@ -6,7 +6,7 @@ import semmle.python.security.strings.Untrusted
* Prevents taint flowing through ntpath.normpath()
* NormalizedPath below handles that case.
*/
class PathSanitizer extends Sanitizer {
deprecated class PathSanitizer extends Sanitizer {
PathSanitizer() { this = "path.sanitizer" }
override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) {
@@ -15,7 +15,7 @@ class PathSanitizer extends Sanitizer {
}
}
private FunctionObject abspath() {
deprecated private FunctionObject abspath() {
exists(ModuleObject os_path | ModuleObject::named("os").attr("path") = os_path |
os_path.attr("abspath") = result
or
@@ -24,18 +24,18 @@ private FunctionObject abspath() {
}
/** A path that has been normalized, but not verified to be safe */
class NormalizedPath extends TaintKind {
deprecated class NormalizedPath extends TaintKind {
NormalizedPath() { this = "normalized.path.injection" }
override string repr() { result = "normalized path" }
}
private predicate abspath_call(CallNode call, ControlFlowNode arg) {
deprecated private predicate abspath_call(CallNode call, ControlFlowNode arg) {
call.getFunction().refersTo(abspath()) and
arg = call.getArg(0)
}
class AbsPath extends DataFlowExtension::DataFlowNode {
deprecated class AbsPath extends DataFlowExtension::DataFlowNode {
AbsPath() { abspath_call(_, this) }
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
@@ -45,7 +45,7 @@ class AbsPath extends DataFlowExtension::DataFlowNode {
}
}
class NormalizedPathSanitizer extends Sanitizer {
deprecated class NormalizedPathSanitizer extends Sanitizer {
NormalizedPathSanitizer() { this = "normalized.path.sanitizer" }
override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) {
@@ -59,7 +59,7 @@ class NormalizedPathSanitizer extends Sanitizer {
* A taint sink that is vulnerable to malicious paths.
* The `vuln` in `open(vuln)` and similar.
*/
class OpenNode extends TaintSink {
deprecated class OpenNode extends TaintSink {
override string toString() { result = "argument to open()" }
OpenNode() {

View File

@@ -11,7 +11,7 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.security.injection.Deserialization
private ModuleObject pickleModule() {
deprecated private ModuleObject pickleModule() {
result.getName() = "pickle"
or
result.getName() = "cPickle"
@@ -19,10 +19,10 @@ private ModuleObject pickleModule() {
result.getName() = "dill"
}
private FunctionObject pickleLoads() { result = pickleModule().attr("loads") }
deprecated private FunctionObject pickleLoads() { result = pickleModule().attr("loads") }
/** `pickle.loads(untrusted)` vulnerability. */
class UnpicklingNode extends DeserializationSink {
deprecated class UnpicklingNode extends DeserializationSink {
override string toString() { result = "unpickling untrusted data" }
UnpicklingNode() {

View File

@@ -11,7 +11,7 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.security.SQL
private StringObject first_part(ControlFlowNode command) {
deprecated private StringObject first_part(ControlFlowNode command) {
command.(BinaryExprNode).getOp() instanceof Add and
command.(BinaryExprNode).getLeft().refersTo(result)
or
@@ -26,7 +26,7 @@ private StringObject first_part(ControlFlowNode command) {
}
/** Holds if `command` appears to be a SQL command string of which `inject` is a part. */
predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject) {
deprecated predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject) {
exists(string prefix |
inject = command.getAChild*() and
first_part(command).getText().regexpMatch(" *" + prefix + ".*")
@@ -39,7 +39,7 @@ predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject)
* A taint kind representing a DB cursor.
* This will be overridden to provide specific kinds of DB cursor.
*/
abstract class DbCursor extends TaintKind {
abstract deprecated class DbCursor extends TaintKind {
bindingset[this]
DbCursor() { any() }
@@ -50,7 +50,7 @@ abstract class DbCursor extends TaintKind {
* A part of a string that appears to be a SQL command and is thus
* vulnerable to malicious input.
*/
class SimpleSqlStringInjection extends SqlInjectionSink {
deprecated class SimpleSqlStringInjection extends SqlInjectionSink {
override string toString() { result = "simple SQL string injection" }
SimpleSqlStringInjection() { probable_sql_command(_, this) }
@@ -62,13 +62,13 @@ class SimpleSqlStringInjection extends SqlInjectionSink {
* A taint source representing sources of DB connections.
* This will be overridden to provide specific kinds of DB connection sources.
*/
abstract class DbConnectionSource extends TaintSource { }
abstract deprecated class DbConnectionSource extends TaintSource { }
/**
* A taint sink that is vulnerable to malicious SQL queries.
* The `vuln` in `db.connection.execute(vuln)` and similar.
*/
class DbConnectionExecuteArgument extends SqlInjectionSink {
deprecated class DbConnectionExecuteArgument extends SqlInjectionSink {
override string toString() { result = "db.connection.execute" }
DbConnectionExecuteArgument() {

View File

@@ -11,23 +11,25 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.security.injection.Deserialization
private ModuleObject xmlElementTreeModule() { result.getName() = "xml.etree.ElementTree" }
deprecated private ModuleObject xmlElementTreeModule() {
result.getName() = "xml.etree.ElementTree"
}
private ModuleObject xmlMiniDomModule() { result.getName() = "xml.dom.minidom" }
deprecated private ModuleObject xmlMiniDomModule() { result.getName() = "xml.dom.minidom" }
private ModuleObject xmlPullDomModule() { result.getName() = "xml.dom.pulldom" }
deprecated private ModuleObject xmlPullDomModule() { result.getName() = "xml.dom.pulldom" }
private ModuleObject xmlSaxModule() { result.getName() = "xml.sax" }
deprecated private ModuleObject xmlSaxModule() { result.getName() = "xml.sax" }
private class ExpatParser extends TaintKind {
deprecated private class ExpatParser extends TaintKind {
ExpatParser() { this = "expat.parser" }
}
private FunctionObject expatCreateParseFunction() {
deprecated private FunctionObject expatCreateParseFunction() {
result = ModuleObject::named("xml.parsers.expat").attr("ParserCreate")
}
private class ExpatCreateParser extends TaintSource {
deprecated private class ExpatCreateParser extends TaintSource {
ExpatCreateParser() { expatCreateParseFunction().getACall() = this }
override predicate isSourceOf(TaintKind kind) { kind instanceof ExpatParser }
@@ -35,7 +37,7 @@ private class ExpatCreateParser extends TaintSource {
override string toString() { result = "expat.create.parser" }
}
private FunctionObject xmlFromString() {
deprecated private FunctionObject xmlFromString() {
result = xmlElementTreeModule().attr("fromstring")
or
result = xmlMiniDomModule().attr("parseString")
@@ -46,7 +48,7 @@ private FunctionObject xmlFromString() {
}
/** A (potentially) malicious XML string. */
class ExternalXmlString extends ExternalStringKind {
deprecated class ExternalXmlString extends ExternalStringKind {
ExternalXmlString() { this = "external xml encoded object" }
}
@@ -54,7 +56,7 @@ class ExternalXmlString extends ExternalStringKind {
* A call to an XML library function that is potentially vulnerable to a
* specially crafted XML string.
*/
class XmlLoadNode extends DeserializationSink {
deprecated class XmlLoadNode extends DeserializationSink {
override string toString() { result = "xml.load vulnerability" }
XmlLoadNode() {

View File

@@ -11,10 +11,10 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.security.injection.Deserialization
private FunctionObject yamlLoad() { result = ModuleObject::named("yaml").attr("load") }
deprecated private FunctionObject yamlLoad() { result = ModuleObject::named("yaml").attr("load") }
/** `yaml.load(untrusted)` vulnerability. */
class YamlLoadNode extends DeserializationSink {
deprecated class YamlLoadNode extends DeserializationSink {
override string toString() { result = "yaml.load vulnerability" }
YamlLoadNode() {

View File

@@ -3,7 +3,7 @@ private import Common
import semmle.python.dataflow.TaintTracking
/** An extensible kind of taint representing any kind of string. */
abstract class StringKind extends TaintKind {
abstract deprecated class StringKind extends TaintKind {
bindingset[this]
StringKind() { this = this }
@@ -42,7 +42,7 @@ abstract class StringKind extends TaintKind {
}
}
private class StringEqualitySanitizer extends Sanitizer {
deprecated private class StringEqualitySanitizer extends Sanitizer {
StringEqualitySanitizer() { this = "string equality sanitizer" }
/** The test `if untrusted == "KNOWN_VALUE":` sanitizes `untrusted` on its `true` edge. */
@@ -64,13 +64,13 @@ private class StringEqualitySanitizer extends Sanitizer {
}
/** tonode = ....format(fromnode) */
private predicate str_format(ControlFlowNode fromnode, CallNode tonode) {
deprecated private predicate str_format(ControlFlowNode fromnode, CallNode tonode) {
tonode.getFunction().(AttrNode).getName() = "format" and
tonode.getAnArg() = fromnode
}
/** tonode = codec.[en|de]code(fromnode) */
private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) {
deprecated private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) {
exists(FunctionObject func, string name |
not func.getFunction().isMethod() and
func.getACall() = tonode and
@@ -84,7 +84,7 @@ private predicate encode_decode(ControlFlowNode fromnode, CallNode tonode) {
}
/** tonode = str(fromnode) */
private predicate to_str(ControlFlowNode fromnode, CallNode tonode) {
deprecated private predicate to_str(ControlFlowNode fromnode, CallNode tonode) {
tonode.getAnArg() = fromnode and
(
tonode = ClassValue::bytes().getACall()
@@ -94,7 +94,7 @@ private predicate to_str(ControlFlowNode fromnode, CallNode tonode) {
}
/** tonode = fromnode[:] */
private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
deprecated private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
exists(Slice all |
all = tonode.getIndex().getNode() and
not exists(all.getStart()) and
@@ -104,13 +104,13 @@ private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
}
/** tonode = os.path.join(..., fromnode, ...) */
private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) {
deprecated private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) {
tonode = Value::named("os.path.join").getACall() and
tonode.getAnArg() = fromnode
}
/** tonode = f"... {fromnode} ..." */
private predicate f_string(ControlFlowNode fromnode, ControlFlowNode tonode) {
deprecated private predicate f_string(ControlFlowNode fromnode, ControlFlowNode tonode) {
tonode.getNode().(Fstring).getAValue() = fromnode.getNode()
}

View File

@@ -1,7 +1,7 @@
import python
/* A call that returns a copy (or similar) of the argument */
predicate copy_call(ControlFlowNode fromnode, CallNode tonode) {
deprecated predicate copy_call(ControlFlowNode fromnode, CallNode tonode) {
tonode.getFunction().(AttrNode).getObject("copy") = fromnode
or
exists(ModuleValue copy, string name | name = "copy" or name = "deepcopy" |

View File

@@ -5,7 +5,7 @@ private import Common
/**
* An extensible kind of taint representing an externally controlled string.
*/
abstract class ExternalStringKind extends StringKind {
abstract deprecated class ExternalStringKind extends StringKind {
bindingset[this]
ExternalStringKind() { this = this }
@@ -30,7 +30,7 @@ abstract class ExternalStringKind extends StringKind {
}
/** A kind of "taint", representing a sequence, with a "taint" member */
class ExternalStringSequenceKind extends SequenceKind {
deprecated class ExternalStringSequenceKind extends SequenceKind {
ExternalStringSequenceKind() { this.getItem() instanceof ExternalStringKind }
}
@@ -38,7 +38,7 @@ class ExternalStringSequenceKind extends SequenceKind {
* An hierachical dictionary or list where the entire structure is externally controlled
* This is typically a parsed JSON object.
*/
class ExternalJsonKind extends TaintKind {
deprecated class ExternalJsonKind extends TaintKind {
ExternalJsonKind() { this = "json[" + any(ExternalStringKind key) + "]" }
/** Gets the taint kind for item in this sequence */
@@ -61,7 +61,7 @@ class ExternalJsonKind extends TaintKind {
}
/** A kind of "taint", representing a dictionary mapping keys to tainted strings. */
class ExternalStringDictKind extends DictKind {
deprecated class ExternalStringDictKind extends DictKind {
ExternalStringDictKind() { this.getValue() instanceof ExternalStringKind }
}
@@ -69,12 +69,12 @@ class ExternalStringDictKind extends DictKind {
* A kind of "taint", representing a dictionary mapping keys to sequences of
* tainted strings.
*/
class ExternalStringSequenceDictKind extends DictKind {
deprecated class ExternalStringSequenceDictKind extends DictKind {
ExternalStringSequenceDictKind() { this.getValue() instanceof ExternalStringSequenceKind }
}
/** TaintKind for the result of `urlsplit(tainted_string)` */
class ExternalUrlSplitResult extends ExternalStringSequenceKind {
deprecated class ExternalUrlSplitResult extends ExternalStringSequenceKind {
// https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlsplit
override TaintKind getTaintOfAttribute(string name) {
result = super.getTaintOfAttribute(name)
@@ -103,7 +103,7 @@ class ExternalUrlSplitResult extends ExternalStringSequenceKind {
}
/** TaintKind for the result of `urlparse(tainted_string)` */
class ExternalUrlParseResult extends ExternalStringSequenceKind {
deprecated class ExternalUrlParseResult extends ExternalStringSequenceKind {
// https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlparse
override TaintKind getTaintOfAttribute(string name) {
result = super.getTaintOfAttribute(name)
@@ -134,7 +134,7 @@ class ExternalUrlParseResult extends ExternalStringSequenceKind {
/* Helper for getTaintForStep() */
pragma[noinline]
private predicate json_subscript_taint(
deprecated private predicate json_subscript_taint(
SubscriptNode sub, ControlFlowNode obj, ExternalJsonKind seq, TaintKind key
) {
sub.isLoad() and
@@ -142,12 +142,12 @@ private predicate json_subscript_taint(
key = seq.getValue()
}
private predicate json_load(ControlFlowNode fromnode, CallNode tonode) {
deprecated private predicate json_load(ControlFlowNode fromnode, CallNode tonode) {
tonode = Value::named("json.loads").getACall() and
tonode.getArg(0) = fromnode
}
private predicate urlsplit(ControlFlowNode fromnode, CallNode tonode) {
deprecated private predicate urlsplit(ControlFlowNode fromnode, CallNode tonode) {
// This could be implemented as `exists(FunctionValue` without the explicit six part,
// but then our tests will need to import +100 modules, so for now this slightly
// altered version gets to live on.
@@ -166,7 +166,7 @@ private predicate urlsplit(ControlFlowNode fromnode, CallNode tonode) {
)
}
private predicate urlparse(ControlFlowNode fromnode, CallNode tonode) {
deprecated private predicate urlparse(ControlFlowNode fromnode, CallNode tonode) {
// This could be implemented as `exists(FunctionValue` without the explicit six part,
// but then our tests will need to import +100 modules, so for now this slightly
// altered version gets to live on.
@@ -185,7 +185,7 @@ private predicate urlparse(ControlFlowNode fromnode, CallNode tonode) {
)
}
private predicate parse_qs(ControlFlowNode fromnode, CallNode tonode) {
deprecated private predicate parse_qs(ControlFlowNode fromnode, CallNode tonode) {
// This could be implemented as `exists(FunctionValue` without the explicit six part,
// but then our tests will need to import +100 modules, so for now this slightly
// altered version gets to live on.
@@ -211,7 +211,7 @@ private predicate parse_qs(ControlFlowNode fromnode, CallNode tonode) {
)
}
private predicate parse_qsl(ControlFlowNode fromnode, CallNode tonode) {
deprecated private predicate parse_qsl(ControlFlowNode fromnode, CallNode tonode) {
// This could be implemented as `exists(FunctionValue` without the explicit six part,
// but then our tests will need to import +100 modules, so for now this slightly
// altered version gets to live on.
@@ -238,7 +238,7 @@ private predicate parse_qsl(ControlFlowNode fromnode, CallNode tonode) {
}
/** A kind of "taint", representing an open file-like object from an external source. */
class ExternalFileObject extends TaintKind {
deprecated class ExternalFileObject extends TaintKind {
ExternalStringKind valueKind;
ExternalFileObject() { this = "file[" + valueKind + "]" }
@@ -266,7 +266,7 @@ class ExternalFileObject extends TaintKind {
* - `if splitres.netloc == "KNOWN_VALUE"`
* - `if splitres[0] == "KNOWN_VALUE"`
*/
class UrlsplitUrlparseTempSanitizer extends Sanitizer {
deprecated class UrlsplitUrlparseTempSanitizer extends Sanitizer {
// TODO: remove this once we have better support for named tuples
UrlsplitUrlparseTempSanitizer() { this = "UrlsplitUrlparseTempSanitizer" }

View File

@@ -5,6 +5,6 @@ import External
* A kind of taint representing an externally controlled string.
* This class is a simple sub-class of `ExternalStringKind`.
*/
class UntrustedStringKind extends ExternalStringKind {
deprecated class UntrustedStringKind extends ExternalStringKind {
UntrustedStringKind() { this = "externally controlled string" }
}

View File

@@ -87,7 +87,7 @@ class RangeIterationVariableFact extends PointsToExtension {
}
/* bottle module route constants */
class BottleRoutePointToExtension extends PointsToExtension {
deprecated class BottleRoutePointToExtension extends PointsToExtension {
string name;
BottleRoutePointToExtension() {

View File

@@ -4,13 +4,13 @@ import semmle.python.security.strings.External
import HttpConstants
/** Generic taint source from a http request */
abstract class HttpRequestTaintSource extends TaintSource { }
abstract deprecated class HttpRequestTaintSource extends TaintSource { }
/**
* Taint kind representing the WSGI environment.
* As specified in PEP 3333. https://www.python.org/dev/peps/pep-3333/#environ-variables
*/
class WsgiEnvironment extends TaintKind {
deprecated class WsgiEnvironment extends TaintKind {
WsgiEnvironment() { this = "wsgi.environment" }
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
@@ -43,7 +43,7 @@ class WsgiEnvironment extends TaintKind {
* A standard morsel object from a HTTP request, a value in a cookie,
* typically an instance of `http.cookies.Morsel`
*/
class UntrustedMorsel extends TaintKind {
deprecated class UntrustedMorsel extends TaintKind {
UntrustedMorsel() { this = "http.Morsel" }
override TaintKind getTaintOfAttribute(string name) {
@@ -53,7 +53,7 @@ class UntrustedMorsel extends TaintKind {
}
/** A standard cookie object from a HTTP request, typically an instance of `http.cookies.SimpleCookie` */
class UntrustedCookie extends TaintKind {
deprecated class UntrustedCookie extends TaintKind {
UntrustedCookie() { this = "http.Cookie" }
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
@@ -62,7 +62,7 @@ class UntrustedCookie extends TaintKind {
}
}
abstract class CookieOperation extends @py_flow_node {
abstract deprecated class CookieOperation extends @py_flow_node {
/** Gets a textual representation of this element. */
abstract string toString();
@@ -71,20 +71,20 @@ abstract class CookieOperation extends @py_flow_node {
abstract ControlFlowNode getValue();
}
abstract class CookieGet extends CookieOperation { }
abstract deprecated class CookieGet extends CookieOperation { }
abstract class CookieSet extends CookieOperation { }
abstract deprecated class CookieSet extends CookieOperation { }
/** Generic taint sink in a http response */
abstract class HttpResponseTaintSink extends TaintSink {
abstract deprecated class HttpResponseTaintSink extends TaintSink {
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
abstract class HttpRedirectTaintSink extends TaintSink {
abstract deprecated class HttpRedirectTaintSink extends TaintSink {
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
module Client {
deprecated module Client {
// TODO: user-input in other than URL:
// - `data`, `json` for `requests.post`
// - `body` for `HTTPConnection.request`

View File

@@ -1,5 +1,7 @@
/** Gets an HTTP verb, in upper case */
string httpVerb() { result in ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"] }
deprecated string httpVerb() {
result in ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"]
}
/** Gets an HTTP verb, in lower case */
string httpVerbLower() { result = httpVerb().toLowerCase() }
deprecated string httpVerbLower() { result = httpVerb().toLowerCase() }

View File

@@ -3,16 +3,16 @@ import semmle.python.web.Http
import semmle.python.types.Extensions
/** The bottle module */
ModuleValue theBottleModule() { result = Module::named("bottle") }
deprecated ModuleValue theBottleModule() { result = Module::named("bottle") }
/** The bottle.Bottle class */
ClassValue theBottleClass() { result = theBottleModule().attr("Bottle") }
deprecated ClassValue theBottleClass() { result = theBottleModule().attr("Bottle") }
/**
* Holds if `route` is routed to `func`
* by decorating `func` with `app.route(route)` or `route(route)`
*/
predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func) {
deprecated predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func) {
exists(CallNode decorator_call, string name |
route_call.getFunction().(AttrNode).getObject(name).pointsTo().getClass() = theBottleClass() or
route_call.getFunction().pointsTo(theBottleModule().attr(name))
@@ -24,7 +24,7 @@ predicate bottle_route(CallNode route_call, ControlFlowNode route, Function func
)
}
class BottleRoute extends ControlFlowNode {
deprecated class BottleRoute extends ControlFlowNode {
BottleRoute() { bottle_route(this, _, _) }
string getUrl() {

View File

@@ -9,12 +9,12 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.bottle.General
FunctionValue bottle_redirect() { result = theBottleModule().attr("redirect") }
deprecated FunctionValue bottle_redirect() { result = theBottleModule().attr("redirect") }
/**
* Represents an argument to the `bottle.redirect` function.
*/
class BottleRedirect extends TaintSink {
deprecated class BottleRedirect extends TaintSink {
override string toString() { result = "bottle.redirect" }
BottleRedirect() {

View File

@@ -4,9 +4,9 @@ import semmle.python.security.strings.External
import semmle.python.web.Http
import semmle.python.web.bottle.General
private Value theBottleRequestObject() { result = theBottleModule().attr("request") }
deprecated private Value theBottleRequestObject() { result = theBottleModule().attr("request") }
class BottleRequestKind extends TaintKind {
deprecated class BottleRequestKind extends TaintKind {
BottleRequestKind() { this = "bottle.request" }
override TaintKind getTaintOfAttribute(string name) {
@@ -21,13 +21,13 @@ class BottleRequestKind extends TaintKind {
}
}
private class RequestSource extends HttpRequestTaintSource {
deprecated private class RequestSource extends HttpRequestTaintSource {
RequestSource() { this.(ControlFlowNode).pointsTo(theBottleRequestObject()) }
override predicate isSourceOf(TaintKind kind) { kind instanceof BottleRequestKind }
}
class BottleFormsDict extends TaintKind {
deprecated class BottleFormsDict extends TaintKind {
BottleFormsDict() { this = "bottle.FormsDict" }
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
@@ -48,7 +48,7 @@ class BottleFormsDict extends TaintKind {
}
}
class FileUpload extends TaintKind {
deprecated class FileUpload extends TaintKind {
FileUpload() { this = "bottle.FileUpload" }
override TaintKind getTaintOfAttribute(string name) {
@@ -60,7 +60,7 @@ class FileUpload extends TaintKind {
}
}
class UntrustedFile extends TaintKind {
deprecated class UntrustedFile extends TaintKind {
UntrustedFile() { this = "Untrusted file" }
}
@@ -69,7 +69,7 @@ class UntrustedFile extends TaintKind {
// Move UntrustedFile to shared location
//
/** Parameter to a bottle request handler function */
class BottleRequestParameter extends HttpRequestTaintSource {
deprecated class BottleRequestParameter extends HttpRequestTaintSource {
BottleRequestParameter() {
exists(BottleRoute route | route.getANamedArgument() = this.(ControlFlowNode).getNode())
}

View File

@@ -9,13 +9,13 @@ import semmle.python.web.bottle.General
* This isn't really a "taint", but we use the value tracking machinery to
* track the flow of response objects.
*/
class BottleResponse extends TaintKind {
deprecated class BottleResponse extends TaintKind {
BottleResponse() { this = "bottle.response" }
}
private Value theBottleResponseObject() { result = theBottleModule().attr("response") }
deprecated private Value theBottleResponseObject() { result = theBottleModule().attr("response") }
class BottleResponseBodyAssignment extends HttpResponseTaintSink {
deprecated class BottleResponseBodyAssignment extends HttpResponseTaintSink {
BottleResponseBodyAssignment() {
exists(DefinitionNode lhs |
lhs.getValue() = this and
@@ -26,7 +26,7 @@ class BottleResponseBodyAssignment extends HttpResponseTaintSink {
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}
class BottleHandlerFunctionResult extends HttpResponseTaintSink {
deprecated class BottleHandlerFunctionResult extends HttpResponseTaintSink {
BottleHandlerFunctionResult() {
exists(BottleRoute route, Return ret |
ret.getScope() = route.getFunction() and
@@ -39,7 +39,7 @@ class BottleHandlerFunctionResult extends HttpResponseTaintSink {
override string toString() { result = "bottle handler function result" }
}
class BottleCookieSet extends CookieSet, CallNode {
deprecated class BottleCookieSet extends CookieSet, CallNode {
BottleCookieSet() {
any(BottleResponse r).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
}

View File

@@ -1,11 +1,11 @@
import python
import semmle.python.web.Http
module CherryPy {
deprecated module CherryPy {
FunctionValue expose() { result = Value::named("cherrypy.expose") }
}
class CherryPyExposedFunction extends Function {
deprecated class CherryPyExposedFunction extends Function {
CherryPyExposedFunction() {
this.getADecorator().pointsTo(CherryPy::expose())
or
@@ -13,7 +13,7 @@ class CherryPyExposedFunction extends Function {
}
}
class CherryPyRoute extends CallNode {
deprecated class CherryPyRoute extends CallNode {
CherryPyRoute() {
/* cherrypy.quickstart(root, script_name, config) */
Value::named("cherrypy.quickstart").(FunctionValue).getACall() = this

View File

@@ -5,7 +5,7 @@ import semmle.python.web.Http
import semmle.python.web.cherrypy.General
/** The cherrypy.request local-proxy object */
class CherryPyRequest extends TaintKind {
deprecated class CherryPyRequest extends TaintKind {
CherryPyRequest() { this = "cherrypy.request" }
override TaintKind getTaintOfAttribute(string name) {
@@ -20,7 +20,7 @@ class CherryPyRequest extends TaintKind {
}
}
class CherryPyExposedFunctionParameter extends HttpRequestTaintSource {
deprecated class CherryPyExposedFunctionParameter extends HttpRequestTaintSource {
CherryPyExposedFunctionParameter() {
exists(Parameter p |
p = any(CherryPyExposedFunction f).getAnArg() and
@@ -34,7 +34,7 @@ class CherryPyExposedFunctionParameter extends HttpRequestTaintSource {
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
}
class CherryPyRequestSource extends HttpRequestTaintSource {
deprecated class CherryPyRequestSource extends HttpRequestTaintSource {
CherryPyRequestSource() { this.(ControlFlowNode).pointsTo(Value::named("cherrypy.request")) }
override predicate isSourceOf(TaintKind kind) { kind instanceof CherryPyRequest }

View File

@@ -4,7 +4,7 @@ import semmle.python.security.strings.Untrusted
import semmle.python.web.Http
import semmle.python.web.cherrypy.General
class CherryPyExposedFunctionResult extends HttpResponseTaintSink {
deprecated class CherryPyExposedFunctionResult extends HttpResponseTaintSink {
CherryPyExposedFunctionResult() {
exists(Return ret |
ret.getScope() instanceof CherryPyExposedFunction and

View File

@@ -6,7 +6,7 @@
import python
private import semmle.python.web.Http
class RequestsHttpRequest extends Client::HttpRequest, CallNode {
deprecated class RequestsHttpRequest extends Client::HttpRequest, CallNode {
CallableValue func;
string method;

View File

@@ -1,7 +1,7 @@
import python
private import semmle.python.web.Http
ClassValue httpConnectionClass() {
deprecated ClassValue httpConnectionClass() {
// Python 2
result = Value::named("httplib.HTTPConnection")
or
@@ -18,7 +18,7 @@ ClassValue httpConnectionClass() {
result = Value::named("six.moves.http_client.HTTPSConnection")
}
class HttpConnectionHttpRequest extends Client::HttpRequest, CallNode {
deprecated class HttpConnectionHttpRequest extends Client::HttpRequest, CallNode {
CallNode constructor_call;
CallableValue func;

View File

@@ -4,16 +4,18 @@ import semmle.python.security.injection.Sql
/**
* A taint kind representing a django cursor object.
*/
class DjangoDbCursor extends DbCursor {
deprecated class DjangoDbCursor extends DbCursor {
DjangoDbCursor() { this = "django.db.connection.cursor" }
}
private Value theDjangoConnectionObject() { result = Value::named("django.db.connection") }
deprecated private Value theDjangoConnectionObject() {
result = Value::named("django.db.connection")
}
/**
* A kind of taint source representing sources of django cursor objects.
*/
class DjangoDbCursorSource extends DbConnectionSource {
deprecated class DjangoDbCursorSource extends DbConnectionSource {
DjangoDbCursorSource() {
exists(AttrNode cursor |
this.(CallNode).getFunction() = cursor and
@@ -26,13 +28,15 @@ class DjangoDbCursorSource extends DbConnectionSource {
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbCursor }
}
ClassValue theDjangoRawSqlClass() { result = Value::named("django.db.models.expressions.RawSQL") }
deprecated ClassValue theDjangoRawSqlClass() {
result = Value::named("django.db.models.expressions.RawSQL")
}
/**
* A sink of taint on calls to `django.db.models.expressions.RawSQL`. This
* allows arbitrary SQL statements to be executed, which is a security risk.
*/
class DjangoRawSqlSink extends SqlInjectionSink {
deprecated class DjangoRawSqlSink extends SqlInjectionSink {
DjangoRawSqlSink() {
exists(CallNode call |
call = theDjangoRawSqlClass().getACall() and

View File

@@ -5,7 +5,7 @@ import semmle.python.web.Http
// TODO: Since django uses `path = partial(...)`, our analysis doesn't understand this is
// a FunctionValue, so we can't use `FunctionValue.getArgumentForCall`
// https://github.com/django/django/blob/master/django/urls/conf.py#L76
abstract class DjangoRoute extends CallNode {
abstract deprecated class DjangoRoute extends CallNode {
DjangoViewHandler getViewHandler() {
result = view_handler_from_view_arg(this.getArg(1))
or
@@ -26,7 +26,7 @@ abstract class DjangoRoute extends CallNode {
* https://docs.djangoproject.com/en/1.11/topics/http/views/
* https://docs.djangoproject.com/en/3.0/topics/http/views/
*/
class DjangoViewHandler extends PythonFunctionValue {
deprecated class DjangoViewHandler extends PythonFunctionValue {
/** Gets the index of the 'request' argument */
int getRequestArgIndex() { result = 0 }
}
@@ -36,7 +36,7 @@ class DjangoViewHandler extends PythonFunctionValue {
* https://docs.djangoproject.com/en/1.11/topics/class-based-views/
* https://docs.djangoproject.com/en/3.0/topics/class-based-views/
*/
private class DjangoViewClass extends ClassValue {
deprecated private class DjangoViewClass extends ClassValue {
DjangoViewClass() {
Value::named("django.views.generic.View") = this.getASuperType()
or
@@ -44,7 +44,7 @@ private class DjangoViewClass extends ClassValue {
}
}
class DjangoClassBasedViewHandler extends DjangoViewHandler {
deprecated class DjangoClassBasedViewHandler extends DjangoViewHandler {
DjangoClassBasedViewHandler() { exists(DjangoViewClass cls | cls.lookup(httpVerbLower()) = this) }
override int getRequestArgIndex() {
@@ -57,7 +57,7 @@ class DjangoClassBasedViewHandler extends DjangoViewHandler {
* Gets the function that will handle requests when `view_arg` is used as the view argument to a
* django route. That is, this methods handles Class-based Views and its `as_view()` function.
*/
private DjangoViewHandler view_handler_from_view_arg(ControlFlowNode view_arg) {
deprecated private DjangoViewHandler view_handler_from_view_arg(ControlFlowNode view_arg) {
// Function-based view
result = view_arg.pointsTo()
or
@@ -70,11 +70,11 @@ private DjangoViewHandler view_handler_from_view_arg(ControlFlowNode view_arg) {
// We need this "dummy" class, since otherwise the regex argument would not be considered
// a regex (RegexString is abstract)
class DjangoRouteRegex extends RegexString {
deprecated class DjangoRouteRegex extends RegexString {
DjangoRouteRegex() { exists(DjangoRegexRoute route | route.getRouteArg() = this.getAFlowNode()) }
}
class DjangoRegexRoute extends DjangoRoute {
deprecated class DjangoRegexRoute extends DjangoRoute {
ControlFlowNode route;
DjangoRegexRoute() {
@@ -109,7 +109,7 @@ class DjangoRegexRoute extends DjangoRoute {
}
}
class DjangoPathRoute extends DjangoRoute {
deprecated class DjangoPathRoute extends DjangoRoute {
ControlFlowNode route;
DjangoPathRoute() {

View File

@@ -5,12 +5,12 @@ import semmle.python.web.Http
import semmle.python.security.injection.Sql
/** A django model class */
class DjangoModel extends ClassValue {
deprecated class DjangoModel extends ClassValue {
DjangoModel() { Value::named("django.db.models.Model") = this.getASuperType() }
}
/** A "taint" for django database tables */
class DjangoDbTableObjects extends TaintKind {
deprecated class DjangoDbTableObjects extends TaintKind {
DjangoDbTableObjects() { this = "django.db.models.Model.objects" }
override TaintKind getTaintOfMethodResult(string name) {
@@ -24,7 +24,7 @@ class DjangoDbTableObjects extends TaintKind {
}
/** Django model objects, which are sources of django database table "taint" */
class DjangoModelObjects extends TaintSource {
deprecated class DjangoModelObjects extends TaintSource {
DjangoModelObjects() {
this.(AttrNode).isLoad() and this.(AttrNode).getObject("objects").pointsTo(any(DjangoModel m))
}
@@ -38,7 +38,7 @@ class DjangoModelObjects extends TaintSource {
* A call to the `raw` method on a django model. This allows a raw SQL query
* to be sent to the database, which is a security risk.
*/
class DjangoModelRawCall extends SqlInjectionSink {
deprecated class DjangoModelRawCall extends SqlInjectionSink {
DjangoModelRawCall() {
exists(CallNode raw_call, ControlFlowNode queryset | this = raw_call.getArg(0) |
raw_call.getFunction().(AttrNode).getObject("raw") = queryset and
@@ -55,7 +55,7 @@ class DjangoModelRawCall extends SqlInjectionSink {
* A call to the `extra` method on a django model. This allows a raw SQL query
* to be sent to the database, which is a security risk.
*/
class DjangoModelExtraCall extends SqlInjectionSink {
deprecated class DjangoModelExtraCall extends SqlInjectionSink {
DjangoModelExtraCall() {
exists(CallNode extra_call, ControlFlowNode queryset | this = extra_call.getArg(0) |
extra_call.getFunction().(AttrNode).getObject("extra") = queryset and

View File

@@ -13,7 +13,7 @@ private import semmle.python.web.Http
/**
* The URL argument for a call to the `django.shortcuts.redirect` function.
*/
class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink {
deprecated class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink {
override string toString() { result = "DjangoShortcutsRedirectSink" }
DjangoShortcutsRedirectSink() {
@@ -27,7 +27,7 @@ deprecated class DjangoRedirect = DjangoShortcutsRedirectSink;
/**
* The URL argument when instantiating a Django Redirect Response.
*/
class DjangoRedirectResponseSink extends HttpRedirectTaintSink {
deprecated class DjangoRedirectResponseSink extends HttpRedirectTaintSink {
DjangoRedirectResponseSink() {
exists(CallNode call | call = any(DjangoRedirectResponseClass cls).getACall() |
this = call.getArg(0)

View File

@@ -4,7 +4,7 @@ import semmle.python.web.Http
import semmle.python.web.django.General
/** A django.request.HttpRequest object */
class DjangoRequest extends TaintKind {
deprecated class DjangoRequest extends TaintKind {
DjangoRequest() { this = "django.request.HttpRequest" }
override TaintKind getTaintOfAttribute(string name) {
@@ -20,13 +20,13 @@ class DjangoRequest extends TaintKind {
/* Helper for getTaintForStep() */
pragma[noinline]
private predicate subscript_taint(SubscriptNode sub, ControlFlowNode obj, TaintKind kind) {
deprecated private predicate subscript_taint(SubscriptNode sub, ControlFlowNode obj, TaintKind kind) {
sub.getObject() = obj and
kind instanceof ExternalStringKind
}
/** A django.request.QueryDict object */
class DjangoQueryDict extends TaintKind {
deprecated class DjangoQueryDict extends TaintKind {
DjangoQueryDict() { this = "django.http.request.QueryDict" }
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
@@ -40,7 +40,7 @@ class DjangoQueryDict extends TaintKind {
}
/** A Django request parameter */
class DjangoRequestSource extends HttpRequestTaintSource {
deprecated class DjangoRequestSource extends HttpRequestTaintSource {
DjangoRequestSource() {
exists(DjangoRoute route, DjangoViewHandler view, int request_arg_index |
route.getViewHandler() = view and
@@ -55,7 +55,7 @@ class DjangoRequestSource extends HttpRequestTaintSource {
}
/** An argument specified in a url routing table */
class DjangoRequestParameter extends HttpRequestTaintSource {
deprecated class DjangoRequestParameter extends HttpRequestTaintSource {
DjangoRequestParameter() {
exists(DjangoRoute route, Function f, DjangoViewHandler view, int request_arg_index |
route.getViewHandler() = view and

View File

@@ -15,12 +15,12 @@ private import semmle.python.web.Http
deprecated class DjangoResponse = DjangoResponseKind;
/** INTERNAL class used for tracking a django response object. */
private class DjangoResponseKind extends TaintKind {
deprecated private class DjangoResponseKind extends TaintKind {
DjangoResponseKind() { this = "django.response.HttpResponse" }
}
/** INTERNAL taint-source used for tracking a django response object. */
private class DjangoResponseSource extends TaintSource {
deprecated private class DjangoResponseSource extends TaintSource {
DjangoResponseSource() { exists(DjangoContentResponseClass cls | cls.getACall() = this) }
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponseKind }
@@ -29,7 +29,7 @@ private class DjangoResponseSource extends TaintSource {
}
/** A write to a django response, which is vulnerable to external data (xss) */
class DjangoResponseWrite extends HttpResponseTaintSink {
deprecated class DjangoResponseWrite extends HttpResponseTaintSink {
DjangoResponseWrite() {
exists(AttrNode meth, CallNode call |
call.getFunction() = meth and
@@ -46,7 +46,7 @@ class DjangoResponseWrite extends HttpResponseTaintSink {
/**
* An argument to initialization of a django response.
*/
class DjangoResponseContent extends HttpResponseTaintSink {
deprecated class DjangoResponseContent extends HttpResponseTaintSink {
DjangoContentResponseClass cls;
CallNode call;
@@ -63,7 +63,7 @@ class DjangoResponseContent extends HttpResponseTaintSink {
/**
* An argument to initialization of a django response, which is vulnerable to external data (XSS).
*/
class DjangoResponseContentXSSVulnerable extends DjangoResponseContent {
deprecated class DjangoResponseContentXSSVulnerable extends DjangoResponseContent {
override DjangoXSSVulnerableResponseClass cls;
DjangoResponseContentXSSVulnerable() {
@@ -76,7 +76,7 @@ class DjangoResponseContentXSSVulnerable extends DjangoResponseContent {
}
}
class DjangoCookieSet extends CookieSet, CallNode {
deprecated class DjangoCookieSet extends CookieSet, CallNode {
DjangoCookieSet() {
any(DjangoResponseKind r).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
}

View File

@@ -13,7 +13,7 @@ deprecated ClassValue theDjangoHttpRedirectClass() {
}
/** A class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */
class DjangoRedirectResponseClass extends ClassValue {
deprecated class DjangoRedirectResponseClass extends ClassValue {
DjangoRedirectResponseClass() {
exists(ClassValue redirect_base |
// version 1.x
@@ -31,7 +31,7 @@ class DjangoRedirectResponseClass extends ClassValue {
* A class that is a Django Response, which can contain content.
* A subclass of `django.http.HttpResponse` that is not a `DjangoRedirectResponseClass`.
*/
class DjangoContentResponseClass extends ClassValue {
deprecated class DjangoContentResponseClass extends ClassValue {
ClassValue base;
DjangoContentResponseClass() {
@@ -59,7 +59,7 @@ class DjangoContentResponseClass extends ClassValue {
}
/** A class that is a Django Response, and is vulnerable to XSS. */
class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass {
deprecated class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass {
DjangoXSSVulnerableResponseClass() {
// We want to avoid FPs on subclasses that are not exposed to XSS, for example `JsonResponse`.
// The easiest way is to disregard any subclass that has a special `__init__` method.

View File

@@ -2,21 +2,23 @@ import python
import semmle.python.web.Http
/** The falcon API class */
ClassValue theFalconAPIClass() { result = Value::named("falcon.API") }
deprecated ClassValue theFalconAPIClass() { result = Value::named("falcon.API") }
/** Holds if `route` is routed to `resource` */
private predicate api_route(CallNode route_call, ControlFlowNode route, ClassValue resource) {
deprecated private predicate api_route(
CallNode route_call, ControlFlowNode route, ClassValue resource
) {
route_call.getFunction().(AttrNode).getObject("add_route").pointsTo().getClass() =
theFalconAPIClass() and
route_call.getArg(0) = route and
route_call.getArg(1).pointsTo().getClass() = resource
}
private predicate route(FalconRoute route, Function target, string funcname) {
deprecated private predicate route(FalconRoute route, Function target, string funcname) {
route.getResourceClass().lookup("on_" + funcname).(FunctionValue).getScope() = target
}
class FalconRoute extends ControlFlowNode {
deprecated class FalconRoute extends ControlFlowNode {
FalconRoute() { api_route(this, _, _) }
string getUrl() {
@@ -31,7 +33,7 @@ class FalconRoute extends ControlFlowNode {
FalconHandlerFunction getHandlerFunction(string method) { route(this, result, method) }
}
class FalconHandlerFunction extends Function {
deprecated class FalconHandlerFunction extends Function {
FalconHandlerFunction() { route(_, this, _) }
private string methodName() { route(_, this, result) }

View File

@@ -5,7 +5,7 @@ import semmle.python.web.falcon.General
import semmle.python.security.strings.External
/** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */
class FalconRequest extends TaintKind {
deprecated class FalconRequest extends TaintKind {
FalconRequest() { this = "falcon.request" }
override TaintKind getTaintOfAttribute(string name) {
@@ -29,7 +29,7 @@ class FalconRequest extends TaintKind {
}
}
class FalconRequestParameter extends HttpRequestTaintSource {
deprecated class FalconRequestParameter extends HttpRequestTaintSource {
FalconRequestParameter() {
exists(FalconHandlerFunction f | f.getRequest() = this.(ControlFlowNode).getNode())
}

View File

@@ -5,12 +5,12 @@ import semmle.python.web.falcon.General
import semmle.python.security.strings.External
/** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */
class FalconResponse extends TaintKind {
deprecated class FalconResponse extends TaintKind {
FalconResponse() { this = "falcon.response" }
}
/** Only used internally to track the response parameter */
private class FalconResponseParameter extends TaintSource {
deprecated private class FalconResponseParameter extends TaintSource {
FalconResponseParameter() {
exists(FalconHandlerFunction f | f.getResponse() = this.(ControlFlowNode).getNode())
}
@@ -18,7 +18,7 @@ private class FalconResponseParameter extends TaintSource {
override predicate isSourceOf(TaintKind k) { k instanceof FalconResponse }
}
class FalconResponseBodySink extends HttpResponseTaintSink {
deprecated class FalconResponseBodySink extends HttpResponseTaintSink {
FalconResponseBodySink() {
exists(AttrNode attr | any(FalconResponse f).taints(attr.getObject("body")) |
attr.(DefinitionNode).getValue() = this

View File

@@ -3,18 +3,18 @@ import semmle.python.web.Http
import semmle.python.web.flask.Response
/** The flask app class */
ClassValue theFlaskClass() { result = Value::named("flask.Flask") }
deprecated ClassValue theFlaskClass() { result = Value::named("flask.Flask") }
/** The flask MethodView class */
ClassValue theFlaskMethodViewClass() { result = Value::named("flask.views.MethodView") }
deprecated ClassValue theFlaskMethodViewClass() { result = Value::named("flask.views.MethodView") }
ClassValue theFlaskReponseClass() { result = Value::named("flask.Response") }
deprecated ClassValue theFlaskReponseClass() { result = Value::named("flask.Response") }
/**
* Holds if `route` is routed to `func`
* by decorating `func` with `app.route(route)`
*/
predicate app_route(ControlFlowNode route, Function func) {
deprecated predicate app_route(ControlFlowNode route, Function func) {
exists(CallNode route_call, CallNode decorator_call |
route_call.getFunction().(AttrNode).getObject("route").pointsTo().getClass() = theFlaskClass() and
decorator_call.getFunction() = route_call and
@@ -24,7 +24,7 @@ predicate app_route(ControlFlowNode route, Function func) {
}
/* Helper for add_url_rule */
private predicate add_url_rule_call(ControlFlowNode regex, ControlFlowNode callable) {
deprecated private predicate add_url_rule_call(ControlFlowNode regex, ControlFlowNode callable) {
exists(CallNode call |
call.getFunction().(AttrNode).getObject("add_url_rule").pointsTo().getClass() = theFlaskClass() and
regex = call.getArg(0)
@@ -35,7 +35,7 @@ private predicate add_url_rule_call(ControlFlowNode regex, ControlFlowNode calla
}
/** Holds if urls matching `regex` are routed to `func` */
predicate add_url_rule(ControlFlowNode regex, Function func) {
deprecated predicate add_url_rule(ControlFlowNode regex, Function func) {
exists(ControlFlowNode callable | add_url_rule_call(regex, callable) |
exists(PythonFunctionValue f | f.getScope() = func and callable.pointsTo(f))
or
@@ -51,14 +51,14 @@ predicate add_url_rule(ControlFlowNode regex, Function func) {
* Holds if urls matching `regex` are routed to `func` using
* any of flask's routing mechanisms.
*/
predicate flask_routing(ControlFlowNode regex, Function func) {
deprecated predicate flask_routing(ControlFlowNode regex, Function func) {
app_route(regex, func)
or
add_url_rule(regex, func)
}
/** A class that extends flask.views.MethodView */
private class MethodViewClass extends ClassValue {
deprecated private class MethodViewClass extends ClassValue {
MethodViewClass() { this.getASuperType() = theFlaskMethodViewClass() }
/* As we are restricted to strings for taint kinds, we need to map these classes to strings. */
@@ -68,12 +68,12 @@ private class MethodViewClass extends ClassValue {
TaintKind asTaint() { result = this.taintString() }
}
private class MethodViewTaint extends TaintKind {
deprecated private class MethodViewTaint extends TaintKind {
MethodViewTaint() { any(MethodViewClass cls).taintString() = this }
}
/** A source of method view "taint"s. */
private class AsView extends TaintSource {
deprecated private class AsView extends TaintSource {
AsView() {
exists(ClassValue view_class |
view_class.getASuperType() = theFlaskMethodViewClass() and
@@ -91,7 +91,7 @@ private class AsView extends TaintSource {
}
}
class FlaskCookieSet extends CookieSet, CallNode {
deprecated class FlaskCookieSet extends CookieSet, CallNode {
FlaskCookieSet() {
any(FlaskResponseTaintKind t).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
}

View File

@@ -9,12 +9,12 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.flask.General
FunctionValue flask_redirect() { result = Value::named("flask.redirect") }
deprecated FunctionValue flask_redirect() { result = Value::named("flask.redirect") }
/**
* Represents an argument to the `flask.redirect` function.
*/
class FlaskRedirect extends HttpRedirectTaintSink {
deprecated class FlaskRedirect extends HttpRedirectTaintSink {
override string toString() { result = "flask.redirect" }
FlaskRedirect() {

View File

@@ -3,16 +3,16 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.web.Http
import semmle.python.web.flask.General
private Value theFlaskRequestObject() { result = Value::named("flask.request") }
deprecated private Value theFlaskRequestObject() { result = Value::named("flask.request") }
/** Holds if `attr` is an access of attribute `name` of the flask request object */
private predicate flask_request_attr(AttrNode attr, string name) {
deprecated private predicate flask_request_attr(AttrNode attr, string name) {
attr.isLoad() and
attr.getObject(name).pointsTo(theFlaskRequestObject())
}
/** Source of external data from a flask request */
class FlaskRequestData extends HttpRequestTaintSource {
deprecated class FlaskRequestData extends HttpRequestTaintSource {
FlaskRequestData() {
not this instanceof FlaskRequestArgs and
exists(string name | flask_request_attr(this, name) |
@@ -26,7 +26,7 @@ class FlaskRequestData extends HttpRequestTaintSource {
}
/** Source of dictionary whose values are externally controlled */
class FlaskRequestArgs extends HttpRequestTaintSource {
deprecated class FlaskRequestArgs extends HttpRequestTaintSource {
FlaskRequestArgs() {
exists(string attr | flask_request_attr(this, attr) |
attr in ["args", "form", "values", "files", "headers", "json"]
@@ -39,7 +39,7 @@ class FlaskRequestArgs extends HttpRequestTaintSource {
}
/** Source of dictionary whose values are externally controlled */
class FlaskRequestJson extends HttpRequestTaintSource {
deprecated class FlaskRequestJson extends HttpRequestTaintSource {
FlaskRequestJson() { flask_request_attr(this, "json") }
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalJsonKind }
@@ -57,7 +57,7 @@ class FlaskRequestJson extends HttpRequestTaintSource {
* def hello(name):
* ```
*/
class FlaskRoutedParameter extends HttpRequestTaintSource {
deprecated class FlaskRoutedParameter extends HttpRequestTaintSource {
FlaskRoutedParameter() {
exists(string name, Function func, StrConst url_pattern |
this.(ControlFlowNode).getNode() = func.getArgByName(name) and
@@ -72,7 +72,7 @@ class FlaskRoutedParameter extends HttpRequestTaintSource {
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
}
private string werkzeug_rule_re() {
deprecated private string werkzeug_rule_re() {
// since flask uses werkzeug internally, we are using its routing rules from
// https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151
result =

View File

@@ -7,7 +7,7 @@ import semmle.python.web.flask.General
* A flask response, which is vulnerable to any sort of
* http response malice.
*/
class FlaskRoutedResponse extends HttpResponseTaintSink {
deprecated class FlaskRoutedResponse extends HttpResponseTaintSink {
FlaskRoutedResponse() {
exists(PythonFunctionValue response |
flask_routing(_, response.getScope()) and
@@ -20,7 +20,7 @@ class FlaskRoutedResponse extends HttpResponseTaintSink {
override string toString() { result = "flask.routed.response" }
}
class FlaskResponseArgument extends HttpResponseTaintSink {
deprecated class FlaskResponseArgument extends HttpResponseTaintSink {
FlaskResponseArgument() {
exists(CallNode call |
(
@@ -37,11 +37,11 @@ class FlaskResponseArgument extends HttpResponseTaintSink {
override string toString() { result = "flask.response.argument" }
}
class FlaskResponseTaintKind extends TaintKind {
deprecated class FlaskResponseTaintKind extends TaintKind {
FlaskResponseTaintKind() { this = "flask.Response" }
}
class FlaskResponseConfiguration extends TaintTracking::Configuration {
deprecated class FlaskResponseConfiguration extends TaintTracking::Configuration {
FlaskResponseConfiguration() { this = "Flask response configuration" }
override predicate isSource(DataFlow::Node node, TaintKind kind) {

View File

@@ -9,7 +9,7 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.Http
private ClassValue redirectClass() {
deprecated private ClassValue redirectClass() {
exists(ModuleValue ex | ex.getName() = "pyramid.httpexceptions" |
ex.attr("HTTPFound") = result
or
@@ -20,7 +20,7 @@ private ClassValue redirectClass() {
/**
* Represents an argument to the `tornado.redirect` function.
*/
class PyramidRedirect extends HttpRedirectTaintSink {
deprecated class PyramidRedirect extends HttpRedirectTaintSink {
override string toString() { result = "pyramid.redirect" }
PyramidRedirect() {

View File

@@ -4,14 +4,14 @@ import semmle.python.web.Http
private import semmle.python.web.webob.Request
private import semmle.python.web.pyramid.View
class PyramidRequest extends BaseWebobRequest {
deprecated class PyramidRequest extends BaseWebobRequest {
PyramidRequest() { this = "pyramid.request" }
override ClassValue getType() { result = Value::named("pyramid.request.Request") }
}
/** Source of pyramid request objects */
class PyramidViewArgument extends HttpRequestTaintSource {
deprecated class PyramidViewArgument extends HttpRequestTaintSource {
PyramidViewArgument() {
exists(Function view_func |
is_pyramid_view_function(view_func) and

View File

@@ -9,7 +9,7 @@ private import semmle.python.web.Http
* A pyramid response, which is vulnerable to any sort of
* http response malice.
*/
class PyramidRoutedResponse extends HttpResponseTaintSink {
deprecated class PyramidRoutedResponse extends HttpResponseTaintSink {
PyramidRoutedResponse() {
exists(PythonFunctionValue view |
is_pyramid_view_function(view.getScope()) and
@@ -22,7 +22,7 @@ class PyramidRoutedResponse extends HttpResponseTaintSink {
override string toString() { result = "pyramid.routed.response" }
}
class PyramidCookieSet extends CookieSet, CallNode {
deprecated class PyramidCookieSet extends CookieSet, CallNode {
PyramidCookieSet() {
exists(ControlFlowNode f |
f = this.getFunction().(AttrNode).getObject("set_cookie") and

View File

@@ -1,9 +1,9 @@
import python
ModuleValue thePyramidViewModule() { result.getName() = "pyramid.view" }
deprecated ModuleValue thePyramidViewModule() { result.getName() = "pyramid.view" }
Value thePyramidViewConfig() { result = thePyramidViewModule().attr("view_config") }
deprecated Value thePyramidViewConfig() { result = thePyramidViewModule().attr("view_config") }
predicate is_pyramid_view_function(Function func) {
deprecated predicate is_pyramid_view_function(Function func) {
func.getADecorator().pointsTo().getClass() = thePyramidViewConfig()
}

View File

@@ -9,7 +9,7 @@ import semmle.python.dataflow.TaintTracking
import semmle.python.web.Http
/** Source of BaseHTTPRequestHandler instances. */
class StdLibRequestSource extends HttpRequestTaintSource {
deprecated class StdLibRequestSource extends HttpRequestTaintSource {
StdLibRequestSource() {
exists(ClassValue cls |
cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler")
@@ -24,7 +24,7 @@ class StdLibRequestSource extends HttpRequestTaintSource {
}
/** TaintKind for an instance of BaseHTTPRequestHandler. */
class BaseHTTPRequestHandlerKind extends TaintKind {
deprecated class BaseHTTPRequestHandlerKind extends TaintKind {
BaseHTTPRequestHandlerKind() { this = "BaseHTTPRequestHandlerKind" }
override TaintKind getTaintOfAttribute(string name) {
@@ -40,7 +40,7 @@ class BaseHTTPRequestHandlerKind extends TaintKind {
}
/** TaintKind for headers (instance of HTTPMessage). */
class HTTPMessageKind extends ExternalStringDictKind {
deprecated class HTTPMessageKind extends ExternalStringDictKind {
override TaintKind getTaintOfMethodResult(string name) {
result = super.getTaintOfMethodResult(name)
or
@@ -63,14 +63,14 @@ class HTTPMessageKind extends ExternalStringDictKind {
}
/** Source of parsed HTTP forms (by using the `cgi` module). */
class CgiFieldStorageSource extends HttpRequestTaintSource {
deprecated class CgiFieldStorageSource extends HttpRequestTaintSource {
CgiFieldStorageSource() { this = Value::named("cgi.FieldStorage").getACall() }
override predicate isSourceOf(TaintKind kind) { kind instanceof CgiFieldStorageFormKind }
}
/** TaintKind for a parsed HTTP form. */
class CgiFieldStorageFormKind extends TaintKind {
deprecated class CgiFieldStorageFormKind extends TaintKind {
/*
* There is a slight difference between how we model form/fields and how it is handled by the code.
* In the code
@@ -115,7 +115,7 @@ class CgiFieldStorageFormKind extends TaintKind {
}
/** TaintKind for the field of a parsed HTTP form. */
class CgiFieldStorageFieldKind extends TaintKind {
deprecated class CgiFieldStorageFieldKind extends TaintKind {
CgiFieldStorageFieldKind() { this = "CgiFieldStorageFieldKind" }
override TaintKind getTaintOfAttribute(string name) {

View File

@@ -6,7 +6,7 @@ import python
import semmle.python.dataflow.TaintTracking
import semmle.python.web.Http
private predicate is_wfile(AttrNode wfile) {
deprecated private predicate is_wfile(AttrNode wfile) {
exists(ClassValue cls |
// Python 2
cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler")
@@ -19,7 +19,7 @@ private predicate is_wfile(AttrNode wfile) {
}
/** Sink for `h.wfile.write` where `h` is an instance of BaseHTTPRequestHandler. */
class StdLibWFileWriteSink extends HttpResponseTaintSink {
deprecated class StdLibWFileWriteSink extends HttpResponseTaintSink {
StdLibWFileWriteSink() {
exists(CallNode call |
is_wfile(call.getFunction().(AttrNode).getObject("write")) and
@@ -31,7 +31,7 @@ class StdLibWFileWriteSink extends HttpResponseTaintSink {
}
/** Sink for `h.wfile.writelines` where `h` is an instance of BaseHTTPRequestHandler. */
class StdLibWFileWritelinesSink extends HttpResponseTaintSink {
deprecated class StdLibWFileWritelinesSink extends HttpResponseTaintSink {
StdLibWFileWritelinesSink() {
exists(CallNode call |
is_wfile(call.getFunction().(AttrNode).getObject("writelines")) and

View File

@@ -13,7 +13,7 @@ import Tornado
/**
* Represents an argument to the `tornado.redirect` function.
*/
class TornadoHttpRequestHandlerRedirect extends HttpRedirectTaintSink {
deprecated class TornadoHttpRequestHandlerRedirect extends HttpRedirectTaintSink {
override string toString() { result = "tornado.HttpRequestHandler.redirect" }
TornadoHttpRequestHandlerRedirect() {

View File

@@ -4,7 +4,7 @@ import semmle.python.web.Http
import Tornado
/** A tornado.request.HttpRequest object */
class TornadoRequest extends TaintKind {
deprecated class TornadoRequest extends TaintKind {
TornadoRequest() { this = "tornado.request.HttpRequest" }
override TaintKind getTaintOfAttribute(string name) {
@@ -30,7 +30,7 @@ class TornadoRequest extends TaintKind {
}
}
class TornadoRequestSource extends HttpRequestTaintSource {
deprecated class TornadoRequestSource extends HttpRequestTaintSource {
TornadoRequestSource() { isTornadoRequestHandlerInstance(this.(AttrNode).getObject("request")) }
override string toString() { result = "Tornado request source" }
@@ -38,7 +38,7 @@ class TornadoRequestSource extends HttpRequestTaintSource {
override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoRequest }
}
class TornadoExternalInputSource extends HttpRequestTaintSource {
deprecated class TornadoExternalInputSource extends HttpRequestTaintSource {
TornadoExternalInputSource() {
exists(string name |
name in ["get_argument", "get_query_argument", "get_body_argument", "decode_argument"]
@@ -52,7 +52,7 @@ class TornadoExternalInputSource extends HttpRequestTaintSource {
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
}
class TornadoExternalInputListSource extends HttpRequestTaintSource {
deprecated class TornadoExternalInputListSource extends HttpRequestTaintSource {
TornadoExternalInputListSource() {
exists(string name |
name = "get_arguments" or

View File

@@ -4,11 +4,11 @@ import semmle.python.security.strings.Basic
private import semmle.python.web.Http
import Tornado
class TornadoConnection extends TaintKind {
deprecated class TornadoConnection extends TaintKind {
TornadoConnection() { this = "tornado.http.connection" }
}
class TornadoConnectionSource extends TaintSource {
deprecated class TornadoConnectionSource extends TaintSource {
TornadoConnectionSource() {
isTornadoRequestHandlerInstance(this.(AttrNode).getObject("connection"))
}
@@ -18,7 +18,7 @@ class TornadoConnectionSource extends TaintSource {
override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoConnection }
}
class TornadoConnectionWrite extends HttpResponseTaintSink {
deprecated class TornadoConnectionWrite extends HttpResponseTaintSink {
override string toString() { result = "tornado.connection.write" }
TornadoConnectionWrite() {
@@ -32,7 +32,7 @@ class TornadoConnectionWrite extends HttpResponseTaintSink {
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}
class TornadoHttpRequestHandlerWrite extends HttpResponseTaintSink {
deprecated class TornadoHttpRequestHandlerWrite extends HttpResponseTaintSink {
override string toString() { result = "tornado.HttpRequestHandler.write" }
TornadoHttpRequestHandlerWrite() {

View File

@@ -2,11 +2,11 @@ import python
import semmle.python.dataflow.TaintTracking
import semmle.python.web.Http
private ClassValue theTornadoRequestHandlerClass() {
deprecated private ClassValue theTornadoRequestHandlerClass() {
result = Value::named("tornado.web.RequestHandler")
}
ClassValue aTornadoRequestHandlerClass() {
deprecated ClassValue aTornadoRequestHandlerClass() {
result.getABaseType+() = theTornadoRequestHandlerClass()
}
@@ -14,7 +14,7 @@ ClassValue aTornadoRequestHandlerClass() {
* Holds if `node` is likely to refer to an instance of a tornado
* `RequestHandler` class.
*/
predicate isTornadoRequestHandlerInstance(ControlFlowNode node) {
deprecated predicate isTornadoRequestHandlerInstance(ControlFlowNode node) {
node.pointsTo().getClass() = aTornadoRequestHandlerClass()
or
/*
@@ -30,11 +30,11 @@ predicate isTornadoRequestHandlerInstance(ControlFlowNode node) {
node.(NameNode).isSelf()
}
CallNode callToNamedTornadoRequestHandlerMethod(string name) {
deprecated CallNode callToNamedTornadoRequestHandlerMethod(string name) {
isTornadoRequestHandlerInstance(result.getFunction().(AttrNode).getObject(name))
}
class TornadoCookieSet extends CookieSet, CallNode {
deprecated class TornadoCookieSet extends CookieSet, CallNode {
TornadoCookieSet() {
exists(ControlFlowNode f |
f = this.getFunction().(AttrNode).getObject("set_cookie") and

View File

@@ -3,7 +3,7 @@ import semmle.python.security.strings.External
import semmle.python.web.Http
import TurboGears
private class ValidatedMethodParameter extends Parameter {
deprecated private class ValidatedMethodParameter extends Parameter {
ValidatedMethodParameter() {
exists(string name, TurboGearsControllerMethod method |
method.getArgByName(name) = this and
@@ -12,7 +12,7 @@ private class ValidatedMethodParameter extends Parameter {
}
}
class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource {
deprecated class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource {
UnvalidatedControllerMethodParameter() {
exists(Parameter p |
any(TurboGearsControllerMethod m | not m.getName() = "onerror").getAnArg() = p and

View File

@@ -4,7 +4,7 @@ import semmle.python.security.strings.Basic
import semmle.python.web.Http
import TurboGears
class ControllerMethodReturnValue extends HttpResponseTaintSink {
deprecated class ControllerMethodReturnValue extends HttpResponseTaintSink {
override string toString() { result = "TurboGears ControllerMethodReturnValue" }
ControllerMethodReturnValue() {
@@ -17,7 +17,7 @@ class ControllerMethodReturnValue extends HttpResponseTaintSink {
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}
class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink {
deprecated class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink {
override string toString() { result = "TurboGears ControllerMethodTemplatedReturnValue" }
ControllerMethodTemplatedReturnValue() {

View File

@@ -1,11 +1,15 @@
import python
import semmle.python.dataflow.TaintTracking
private ClassValue theTurboGearsControllerClass() { result = Value::named("tg.TGController") }
deprecated private ClassValue theTurboGearsControllerClass() {
result = Value::named("tg.TGController")
}
ClassValue aTurboGearsControllerClass() { result.getABaseType+() = theTurboGearsControllerClass() }
deprecated ClassValue aTurboGearsControllerClass() {
result.getABaseType+() = theTurboGearsControllerClass()
}
class TurboGearsControllerMethod extends Function {
deprecated class TurboGearsControllerMethod extends Function {
ControlFlowNode decorator;
TurboGearsControllerMethod() {

View File

@@ -4,7 +4,7 @@ import semmle.python.web.Http
import Twisted
/** A twisted.web.http.Request object */
class TwistedRequest extends TaintKind {
deprecated class TwistedRequest extends TaintKind {
TwistedRequest() { this = "twisted.request.http.Request" }
override TaintKind getTaintOfAttribute(string name) {
@@ -21,7 +21,7 @@ class TwistedRequest extends TaintKind {
}
}
class TwistedRequestSource extends HttpRequestTaintSource {
deprecated class TwistedRequestSource extends HttpRequestTaintSource {
TwistedRequestSource() { isTwistedRequestInstance(this) }
override string toString() { result = "Twisted request source" }

View File

@@ -5,7 +5,7 @@ import semmle.python.security.strings.Basic
import Twisted
import Request
class TwistedResponse extends HttpResponseTaintSink {
deprecated class TwistedResponse extends HttpResponseTaintSink {
TwistedResponse() {
exists(PythonFunctionValue func, string name |
isKnownRequestHandlerMethodName(name) and
@@ -25,7 +25,7 @@ class TwistedResponse extends HttpResponseTaintSink {
* object, which affects the properties of the subsequent response sent to this
* request.
*/
class TwistedRequestSetter extends HttpResponseTaintSink {
deprecated class TwistedRequestSetter extends HttpResponseTaintSink {
TwistedRequestSetter() {
exists(CallNode call, ControlFlowNode node, string name |
(

View File

@@ -1,22 +1,24 @@
import python
import semmle.python.dataflow.TaintTracking
private ClassValue theTwistedHttpRequestClass() {
deprecated private ClassValue theTwistedHttpRequestClass() {
result = Value::named("twisted.web.http.Request")
}
private ClassValue theTwistedHttpResourceClass() {
deprecated private ClassValue theTwistedHttpResourceClass() {
result = Value::named("twisted.web.resource.Resource")
}
ClassValue aTwistedRequestHandlerClass() { result.getABaseType+() = theTwistedHttpResourceClass() }
deprecated ClassValue aTwistedRequestHandlerClass() {
result.getABaseType+() = theTwistedHttpResourceClass()
}
FunctionValue getTwistedRequestHandlerMethod(string name) {
deprecated FunctionValue getTwistedRequestHandlerMethod(string name) {
result = aTwistedRequestHandlerClass().declaredAttribute(name)
}
bindingset[name]
predicate isKnownRequestHandlerMethodName(string name) {
deprecated predicate isKnownRequestHandlerMethodName(string name) {
name = "render" or
name.matches("render_%")
}
@@ -25,7 +27,7 @@ predicate isKnownRequestHandlerMethodName(string name) {
* Holds if `node` is likely to refer to an instance of the twisted
* `Request` class.
*/
predicate isTwistedRequestInstance(NameNode node) {
deprecated predicate isTwistedRequestInstance(NameNode node) {
node.pointsTo().getClass() = theTwistedHttpRequestClass()
or
/*

View File

@@ -2,7 +2,7 @@ import python
import semmle.python.dataflow.TaintTracking
import semmle.python.web.Http
abstract class BaseWebobRequest extends TaintKind {
abstract deprecated class BaseWebobRequest extends TaintKind {
bindingset[this]
BaseWebobRequest() { any() }
@@ -31,7 +31,7 @@ abstract class BaseWebobRequest extends TaintKind {
}
}
class WebobRequest extends BaseWebobRequest {
deprecated class WebobRequest extends BaseWebobRequest {
WebobRequest() { this = "webob.Request" }
override ClassValue getType() { result = Value::named("webob.request.Request") }

View File

@@ -0,0 +1,837 @@
/*
* This dbscheme is auto-generated by 'semmle/dbscheme_gen.py'.
* WARNING: Any modifications to this file will be lost.
* Relations can be changed by modifying master.py or
* by adding rules to dbscheme.template
*/
/*
* External artifacts
*/
externalDefects(
unique int id : @externalDefect,
varchar(900) queryPath : string ref,
int location : @location ref,
varchar(900) message : string ref,
float severity : float ref
);
externalMetrics(
unique int id : @externalMetric,
varchar(900) queryPath : string ref,
int location : @location ref,
float value : float ref
);
externalData(
int id : @externalDataElement,
varchar(900) queryPath : string ref,
int column: int ref,
varchar(900) data : string ref
);
snapshotDate(unique date snapshotDate : date ref);
sourceLocationPrefix(varchar(900) prefix : string ref);
/*
* Duplicate code
*/
duplicateCode(
unique int id : @duplication,
varchar(900) relativePath : string ref,
int equivClass : int ref);
similarCode(
unique int id : @similarity,
varchar(900) relativePath : string ref,
int equivClass : int ref);
@duplication_or_similarity = @duplication | @similarity
tokens(
int id : @duplication_or_similarity ref,
int offset : int ref,
int beginLine : int ref,
int beginColumn : int ref,
int endLine : int ref,
int endColumn : int ref);
/*
* Line metrics
*/
py_codelines(int id : @py_scope ref,
int count : int ref);
py_commentlines(int id : @py_scope ref,
int count : int ref);
py_docstringlines(int id : @py_scope ref,
int count : int ref);
py_alllines(int id : @py_scope ref,
int count : int ref);
/*
* Version history
*/
svnentries(
int id : @svnentry,
varchar(500) revision : string ref,
varchar(500) author : string ref,
date revisionDate : date ref,
int changeSize : int ref
)
svnaffectedfiles(
int id : @svnentry ref,
int file : @file ref,
varchar(500) action : string ref
)
svnentrymsg(
int id : @svnentry ref,
varchar(500) message : string ref
)
svnchurn(
int commit : @svnentry ref,
int file : @file ref,
int churnedLines : int ref
)
/****************************
Python dbscheme
****************************/
/*
fromSource(0) = unknown,
fromSource(1) = from source,
fromSource(2) = from library
*/
files(unique int id: @file,
varchar(900) name: string ref,
varchar(900) simple: string ref,
varchar(900) ext: string ref,
int fromSource: int ref);
folders(unique int id: @folder,
varchar(900) name: string ref,
varchar(900) simple: string ref);
@container = @folder | @file;
containerparent(int parent: @container ref,
unique int child: @container ref);
@sourceline = @file | @py_Module;
numlines(int element_id: @sourceline ref,
int num_lines: int ref,
int num_code: int ref,
int num_comment: int ref
);
@location = @location_ast | @location_default ;
locations_default(unique int id: @location_default,
int file: @file ref,
int beginLine: int ref,
int beginColumn: int ref,
int endLine: int ref,
int endColumn: int ref);
locations_ast(unique int id: @location_ast,
int module: @py_Module ref,
int beginLine: int ref,
int beginColumn: int ref,
int endLine: int ref,
int endColumn: int ref);
py_module_path(int module: @py_Module ref, int file: @file ref);
variable(unique int id : @py_variable,
int scope : @py_scope ref,
varchar(1) name : string ref);
py_line_lengths(unique int id : @py_line,
int file: @py_Module ref,
int line : int ref,
int length : int ref);
/* AUTO GENERATED PART STARTS HERE */
/* <Field> Assert.location = 0, location */
/* <Field> Assert.test = 1, expr */
/* <Field> Assert.msg = 2, expr */
/* <Field> Assign.location = 0, location */
/* <Field> Assign.value = 1, expr */
/* <Field> Assign.targets = 2, expr_list */
/* <Field> Attribute.location = 0, location */
/* <Field> Attribute.value = 1, expr */
/* <Field> Attribute.attr = 2, str */
/* <Field> Attribute.ctx = 3, expr_context */
/* <Field> AugAssign.location = 0, location */
/* <Field> AugAssign.operation = 1, BinOp */
/* <Field> BinaryExpr.location = 0, location */
/* <Field> BinaryExpr.left = 1, expr */
/* <Field> BinaryExpr.op = 2, operator */
/* <Field> BinaryExpr.right = 3, expr */
/* <Parent> BinaryExpr = AugAssign */
/* <Field> BoolExpr.location = 0, location */
/* <Field> BoolExpr.op = 1, boolop */
/* <Field> BoolExpr.values = 2, expr_list */
/* <Field> Break.location = 0, location */
/* <Field> Bytes.location = 0, location */
/* <Field> Bytes.s = 1, bytes */
/* <Field> Call.location = 0, location */
/* <Field> Call.func = 1, expr */
/* <Field> Call.args = 2, expr_list */
/* <Field> Call.keywords = 3, keyword_list */
/* <Field> Call.starargs = 4, expr */
/* <Field> Call.kwargs = 5, expr */
/* <Field> Class.name = 0, str */
/* <Field> Class.body = 1, stmt_list */
/* <Parent> Class = ClassExpr */
/* <Field> ClassExpr.location = 0, location */
/* <Field> ClassExpr.name = 1, str */
/* <Field> ClassExpr.bases = 2, expr_list */
/* <Field> ClassExpr.keywords = 3, keyword_list */
/* <Field> ClassExpr.starargs = 4, expr */
/* <Field> ClassExpr.kwargs = 5, expr */
/* <Field> ClassExpr.inner_scope = 6, Class */
/* <Field> Compare.location = 0, location */
/* <Field> Compare.left = 1, expr */
/* <Field> Compare.ops = 2, cmpop_list */
/* <Field> Compare.comparators = 3, expr_list */
/* <Field> Continue.location = 0, location */
/* <Field> Delete.location = 0, location */
/* <Field> Delete.targets = 1, expr_list */
/* <Field> Dict.location = 0, location */
/* <Field> Dict.keys = 1, expr_list */
/* <Field> Dict.values = 2, expr_list */
/* <Field> DictComp.location = 0, location */
/* <Field> DictComp.function = 1, Function */
/* <Field> DictComp.iterable = 2, expr */
/* <Field> Ellipsis.location = 0, location */
/* <Field> ExceptStmt.location = 0, location */
/* <Field> ExceptStmt.type = 1, expr */
/* <Field> ExceptStmt.name = 2, expr */
/* <Field> ExceptStmt.body = 3, stmt_list */
/* <Field> Exec.location = 0, location */
/* <Field> Exec.body = 1, expr */
/* <Field> Exec.globals = 2, expr */
/* <Field> Exec.locals = 3, expr */
/* <Field> ExprStmt.location = 0, location */
/* <Field> ExprStmt.value = 1, expr */
/* <Field> For.location = 0, location */
/* <Field> For.target = 1, expr */
/* <Field> For.iter = 2, expr */
/* <Field> For.body = 3, stmt_list */
/* <Field> For.orelse = 4, stmt_list */
/* <Field> Function.name = 0, str */
/* <Field> Function.args = 1, parameter_list */
/* <Field> Function.vararg = 2, expr */
/* <Field> Function.kwonlyargs = 3, str_list */
/* <Field> Function.kwarg = 4, expr */
/* <Field> Function.body = 5, stmt_list */
/* <Parent> Function = FunctionParent */
/* <Field> FunctionExpr.location = 0, location */
/* <Field> FunctionExpr.name = 1, str */
/* <Field> FunctionExpr.args = 2, arguments */
/* <Field> FunctionExpr.returns = 3, expr */
/* <Field> FunctionExpr.inner_scope = 4, Function */
/* <Field> GeneratorExp.location = 0, location */
/* <Field> GeneratorExp.function = 1, Function */
/* <Field> GeneratorExp.iterable = 2, expr */
/* <Field> Global.location = 0, location */
/* <Field> Global.names = 1, str_list */
/* <Field> If.location = 0, location */
/* <Field> If.test = 1, expr */
/* <Field> If.body = 2, stmt_list */
/* <Field> If.orelse = 3, stmt_list */
/* <Field> IfExp.location = 0, location */
/* <Field> IfExp.test = 1, expr */
/* <Field> IfExp.body = 2, expr */
/* <Field> IfExp.orelse = 3, expr */
/* <Field> Import.location = 0, location */
/* <Field> Import.names = 1, alias_list */
/* <Field> ImportExpr.location = 0, location */
/* <Field> ImportExpr.level = 1, int */
/* <Field> ImportExpr.name = 2, str */
/* <Field> ImportExpr.top = 3, bool */
/* <Field> ImportStar.location = 0, location */
/* <Field> ImportStar.module = 1, expr */
/* <Field> ImportMember.location = 0, location */
/* <Field> ImportMember.module = 1, expr */
/* <Field> ImportMember.name = 2, str */
/* <Field> Lambda.location = 0, location */
/* <Field> Lambda.args = 1, arguments */
/* <Field> Lambda.inner_scope = 2, Function */
/* <Field> List.location = 0, location */
/* <Field> List.elts = 1, expr_list */
/* <Field> List.ctx = 2, expr_context */
/* <Field> ListComp.location = 0, location */
/* <Field> ListComp.function = 1, Function */
/* <Field> ListComp.iterable = 2, expr */
/* <Field> ListComp.generators = 3, comprehension_list */
/* <Field> ListComp.elt = 4, expr */
/* <Field> Module.name = 0, str */
/* <Field> Module.hash = 1, str */
/* <Field> Module.body = 2, stmt_list */
/* <Field> Module.kind = 3, str */
/* <Field> Name.location = 0, location */
/* <Field> Name.variable = 1, variable */
/* <Field> Name.ctx = 2, expr_context */
/* <Parent> Name = ParameterList */
/* <Field> Nonlocal.location = 0, location */
/* <Field> Nonlocal.names = 1, str_list */
/* <Field> Num.location = 0, location */
/* <Field> Num.n = 1, number */
/* <Field> Num.text = 2, number */
/* <Field> Pass.location = 0, location */
/* <Field> Print.location = 0, location */
/* <Field> Print.dest = 1, expr */
/* <Field> Print.values = 2, expr_list */
/* <Field> Print.nl = 3, bool */
/* <Field> Raise.location = 0, location */
/* <Field> Raise.exc = 1, expr */
/* <Field> Raise.cause = 2, expr */
/* <Field> Raise.type = 3, expr */
/* <Field> Raise.inst = 4, expr */
/* <Field> Raise.tback = 5, expr */
/* <Field> Repr.location = 0, location */
/* <Field> Repr.value = 1, expr */
/* <Field> Return.location = 0, location */
/* <Field> Return.value = 1, expr */
/* <Field> Set.location = 0, location */
/* <Field> Set.elts = 1, expr_list */
/* <Field> SetComp.location = 0, location */
/* <Field> SetComp.function = 1, Function */
/* <Field> SetComp.iterable = 2, expr */
/* <Field> Slice.location = 0, location */
/* <Field> Slice.start = 1, expr */
/* <Field> Slice.stop = 2, expr */
/* <Field> Slice.step = 3, expr */
/* <Field> Starred.location = 0, location */
/* <Field> Starred.value = 1, expr */
/* <Field> Starred.ctx = 2, expr_context */
/* <Field> Str.location = 0, location */
/* <Field> Str.s = 1, str */
/* <Field> Subscript.location = 0, location */
/* <Field> Subscript.value = 1, expr */
/* <Field> Subscript.index = 2, expr */
/* <Field> Subscript.ctx = 3, expr_context */
/* <Field> Try.location = 0, location */
/* <Field> Try.body = 1, stmt_list */
/* <Field> Try.orelse = 2, stmt_list */
/* <Field> Try.handlers = 3, stmt_list */
/* <Field> Try.finalbody = 4, stmt_list */
/* <Field> Tuple.location = 0, location */
/* <Field> Tuple.elts = 1, expr_list */
/* <Field> Tuple.ctx = 2, expr_context */
/* <Parent> Tuple = ParameterList */
/* <Field> UnaryExpr.location = 0, location */
/* <Field> UnaryExpr.op = 1, unaryop */
/* <Field> UnaryExpr.operand = 2, expr */
/* <Field> While.location = 0, location */
/* <Field> While.test = 1, expr */
/* <Field> While.body = 2, stmt_list */
/* <Field> While.orelse = 3, stmt_list */
/* <Field> With.location = 0, location */
/* <Field> With.context_expr = 1, expr */
/* <Field> With.optional_vars = 2, expr */
/* <Field> With.body = 3, stmt_list */
/* <Field> Yield.location = 0, location */
/* <Field> Yield.value = 1, expr */
/* <Field> YieldFrom.location = 0, location */
/* <Field> YieldFrom.value = 1, expr */
/* <Field> Alias.value = 0, expr */
/* <Field> Alias.asname = 1, expr */
/* <Parent> Alias = AliasList */
/* <Parent> AliasList = Import */
/* <Field> Arguments.kw_defaults = 0, expr_list */
/* <Field> Arguments.defaults = 1, expr_list */
/* <Field> Arguments.annotations = 2, expr_list */
/* <Field> Arguments.varargannotation = 3, expr */
/* <Field> Arguments.kwargannotation = 4, expr */
/* <Parent> Arguments = ArgumentsParent */
/* <Parent> boolean = BoolParent */
/* <Parent> Boolop = BoolExpr */
/* <Parent> string = Bytes */
/* <Parent> Cmpop = CmpopList */
/* <Parent> CmpopList = Compare */
/* <Field> Comprehension.iter = 0, expr */
/* <Field> Comprehension.target = 1, expr */
/* <Field> Comprehension.ifs = 2, expr_list */
/* <Parent> Comprehension = ComprehensionList */
/* <Parent> ComprehensionList = ListComp */
/* <Field> Expr.location = 0, location */
/* <Parent> Expr = ExprParent */
/* <Parent> ExprContext = ExprContextParent */
/* <Parent> ExprList = ExprListParent */
/* <Parent> int = ImportExpr */
/* <Field> Keyword.arg = 0, str */
/* <Field> Keyword.value = 1, expr */
/* <Parent> Keyword = KeywordList */
/* <Parent> KeywordList = KeywordListParent */
/* <Parent> Location = ExprOrStmt */
/* <Parent> string = Num */
/* <Parent> Operator = BinaryExpr */
/* <Parent> ParameterList = Function */
/* <Field> Stmt.location = 0, location */
/* <Parent> Stmt = StmtList */
/* <Parent> StmtList = StmtListParent */
/* <Parent> string = StrParent */
/* <Parent> StringList = StrListParent */
/* <Parent> Unaryop = UnaryExpr */
/* <Parent> Variable = Name */
py_Classes(unique int id : @py_Class,
unique int parent : @py_ClassExpr ref);
py_Functions(unique int id : @py_Function,
int parent : @py_Function_parent ref,
int idx : int ref);
py_Modules(unique int id : @py_Module);
py_aliases(unique int id : @py_alias,
int parent : @py_alias_list ref,
int idx : int ref);
py_alias_lists(unique int id : @py_alias_list,
unique int parent : @py_Import ref);
py_arguments(unique int id : @py_arguments,
int parent : @py_arguments_parent ref,
int idx : int ref);
py_bools(boolean id : boolean ref,
unique int parent : @py_bool_parent ref);
py_boolops(unique int id : @py_boolop,
int kind: int ref,
unique int parent : @py_BoolExpr ref);
py_bytes(varchar(1) id : string ref,
unique int parent : @py_Bytes ref);
py_cmpops(unique int id : @py_cmpop,
int kind: int ref,
int parent : @py_cmpop_list ref,
int idx : int ref);
py_cmpop_lists(unique int id : @py_cmpop_list,
unique int parent : @py_Compare ref);
py_comprehensions(unique int id : @py_comprehension,
int parent : @py_comprehension_list ref,
int idx : int ref);
py_comprehension_lists(unique int id : @py_comprehension_list,
unique int parent : @py_ListComp ref);
py_exprs(unique int id : @py_expr,
int kind: int ref,
int parent : @py_expr_parent ref,
int idx : int ref);
py_expr_contexts(unique int id : @py_expr_context,
int kind: int ref,
int parent : @py_expr_context_parent ref,
int idx : int ref);
py_expr_lists(unique int id : @py_expr_list,
int parent : @py_expr_list_parent ref,
int idx : int ref);
py_ints(int id : int ref,
unique int parent : @py_ImportExpr ref);
py_keywords(unique int id : @py_keyword,
int parent : @py_keyword_list ref,
int idx : int ref);
py_keyword_lists(unique int id : @py_keyword_list,
unique int parent : @py_keyword_list_parent ref);
py_locations(unique int id : @location ref,
unique int parent : @py_expr_or_stmt ref);
py_numbers(varchar(1) id : string ref,
int parent : @py_Num ref,
int idx : int ref);
py_operators(unique int id : @py_operator,
int kind: int ref,
unique int parent : @py_BinaryExpr ref);
py_parameter_lists(unique int id : @py_parameter_list,
unique int parent : @py_Function ref);
py_stmts(unique int id : @py_stmt,
int kind: int ref,
int parent : @py_stmt_list ref,
int idx : int ref);
py_stmt_lists(unique int id : @py_stmt_list,
int parent : @py_stmt_list_parent ref,
int idx : int ref);
py_strs(varchar(1) id : string ref,
int parent : @py_str_parent ref,
int idx : int ref);
py_str_lists(unique int id : @py_str_list,
int parent : @py_str_list_parent ref,
int idx : int ref);
py_unaryops(unique int id : @py_unaryop,
int kind: int ref,
unique int parent : @py_UnaryExpr ref);
py_variables(int id : @py_variable ref,
unique int parent : @py_Name ref);
@py_Function_parent = @py_DictComp | @py_FunctionExpr | @py_GeneratorExp | @py_Lambda | @py_ListComp | @py_SetComp;
@py_arguments_parent = @py_FunctionExpr | @py_Lambda;
@py_ast_node = @py_Class | @py_Function | @py_Module | @py_expr | @py_stmt;
@py_bool_parent = @py_ImportExpr | @py_Print;
case @py_boolop.kind of
0 = @py_And
| 1 = @py_Or;
case @py_cmpop.kind of
0 = @py_Eq
| 1 = @py_Gt
| 2 = @py_GtE
| 3 = @py_In
| 4 = @py_Is
| 5 = @py_IsNot
| 6 = @py_Lt
| 7 = @py_LtE
| 8 = @py_NotEq
| 9 = @py_NotIn;
case @py_expr.kind of
0 = @py_Attribute
| 1 = @py_BinaryExpr
| 2 = @py_BoolExpr
| 3 = @py_Bytes
| 4 = @py_Call
| 5 = @py_ClassExpr
| 6 = @py_Compare
| 7 = @py_Dict
| 8 = @py_DictComp
| 9 = @py_Ellipsis
| 10 = @py_FunctionExpr
| 11 = @py_GeneratorExp
| 12 = @py_IfExp
| 13 = @py_ImportExpr
| 14 = @py_ImportMember
| 15 = @py_Lambda
| 16 = @py_List
| 17 = @py_ListComp
| 18 = @py_Name
| 19 = @py_Num
| 20 = @py_Repr
| 21 = @py_Set
| 22 = @py_SetComp
| 23 = @py_Slice
| 24 = @py_Starred
| 25 = @py_Str
| 26 = @py_Subscript
| 27 = @py_Tuple
| 28 = @py_UnaryExpr
| 29 = @py_Yield
| 30 = @py_YieldFrom;
case @py_expr_context.kind of
0 = @py_AugLoad
| 1 = @py_AugStore
| 2 = @py_Del
| 3 = @py_Load
| 4 = @py_Param
| 5 = @py_Store;
@py_expr_context_parent = @py_Attribute | @py_List | @py_Name | @py_Starred | @py_Subscript | @py_Tuple;
@py_expr_list_parent = @py_Assign | @py_BoolExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_Delete | @py_Dict | @py_List | @py_Print | @py_Set | @py_Tuple | @py_arguments | @py_comprehension;
@py_expr_or_stmt = @py_expr | @py_stmt;
@py_expr_parent = @py_Assert | @py_Assign | @py_Attribute | @py_AugAssign | @py_BinaryExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_DictComp | @py_ExceptStmt | @py_Exec | @py_Expr_stmt | @py_For | @py_Function | @py_FunctionExpr | @py_GeneratorExp | @py_If | @py_IfExp | @py_ImportMember | @py_ImportStar | @py_ListComp | @py_Print | @py_Raise | @py_Repr | @py_Return | @py_SetComp | @py_Slice | @py_Starred | @py_Subscript | @py_UnaryExpr | @py_While | @py_With | @py_Yield | @py_YieldFrom | @py_alias | @py_arguments | @py_comprehension | @py_expr_list | @py_keyword | @py_parameter_list;
@py_keyword_list_parent = @py_Call | @py_ClassExpr;
case @py_operator.kind of
0 = @py_Add
| 1 = @py_BitAnd
| 2 = @py_BitOr
| 3 = @py_BitXor
| 4 = @py_Div
| 5 = @py_FloorDiv
| 6 = @py_LShift
| 7 = @py_Mod
| 8 = @py_Mult
| 9 = @py_Pow
| 10 = @py_RShift
| 11 = @py_Sub;
@py_parameter = @py_Name | @py_Tuple;
@py_scope = @py_Class | @py_Function | @py_Module;
case @py_stmt.kind of
0 = @py_Assert
| 1 = @py_Assign
| 2 = @py_AugAssign
| 3 = @py_Break
| 4 = @py_Continue
| 5 = @py_Delete
| 6 = @py_ExceptStmt
| 7 = @py_Exec
| 8 = @py_Expr_stmt
| 9 = @py_For
| 10 = @py_Global
| 11 = @py_If
| 12 = @py_Import
| 13 = @py_ImportStar
| 14 = @py_Nonlocal
| 15 = @py_Pass
| 16 = @py_Print
| 17 = @py_Raise
| 18 = @py_Return
| 19 = @py_Try
| 20 = @py_While
| 21 = @py_With;
@py_stmt_list_parent = @py_Class | @py_ExceptStmt | @py_For | @py_Function | @py_If | @py_Module | @py_Try | @py_While | @py_With;
@py_str_list_parent = @py_Function | @py_Global | @py_Nonlocal;
@py_str_parent = @py_Attribute | @py_Class | @py_ClassExpr | @py_Function | @py_FunctionExpr | @py_ImportExpr | @py_ImportMember | @py_Module | @py_Str | @py_keyword | @py_str_list;
case @py_unaryop.kind of
0 = @py_Invert
| 1 = @py_Not
| 2 = @py_UAdd
| 3 = @py_USub;
/*
* End of auto-generated part
*/
/* Map relative names to absolute names for imports */
py_absolute_names(int module : @py_Module ref,
varchar(1) relname : string ref,
varchar(1) absname : string ref);
py_exports(int id : @py_Module ref,
varchar(1) name : string ref);
/* Successor information */
py_successors(int predecessor : @py_flow_node ref,
int successor : @py_flow_node ref);
py_true_successors(int predecessor : @py_flow_node ref,
int successor : @py_flow_node ref);
py_exception_successors(int predecessor : @py_flow_node ref,
int successor : @py_flow_node ref);
py_false_successors(int predecessor : @py_flow_node ref,
int successor : @py_flow_node ref);
py_flow_bb_node(unique int flownode : @py_flow_node,
int realnode : @py_ast_node ref,
int basicblock : @py_flow_node ref,
int index : int ref);
py_scope_flow(int flow : @py_flow_node ref,
int scope : @py_scope ref,
int kind : int ref);
py_idoms(unique int node : @py_flow_node ref,
int immediate_dominator : @py_flow_node ref);
py_ssa_phi(int phi : @py_ssa_var ref,
int arg: @py_ssa_var ref);
py_ssa_var(unique int id : @py_ssa_var,
int var : @py_variable ref);
py_ssa_use(int node: @py_flow_node ref,
int var : @py_ssa_var ref);
py_ssa_defn(unique int id : @py_ssa_var ref,
int node: @py_flow_node ref);
@py_base_var = @py_variable | @py_ssa_var;
py_scopes(unique int node : @py_expr_or_stmt ref,
int scope : @py_scope ref);
py_scope_location(unique int id : @location ref,
unique int scope : @py_scope ref);
py_flags(unique varchar(1) name : string ref,
varchar(1) value : string ref);
py_syntax_error(unique int id : @location ref,
varchar(1) message : string ref);
py_comments(unique int id : @py_comment,
varchar(1) text : string ref,
unique int location : @location ref);
/* Type information support */
py_cobjects(unique int obj : @py_cobject,
int typeof : @py_cobject ref);
py_cmembers(int object : @py_cobject ref,
varchar(1) name : string ref,
int member : @py_cobject ref);
py_citems(int object : @py_cobject ref,
int index : int ref,
int member : @py_cobject ref);
py_cobjectnames(unique int obj : @py_cobject ref,
varchar(1) name : string ref);
py_special_objects(unique int obj : @py_cobject ref,
unique varchar(1) name : string ref);
py_decorated_object(int object : @py_object ref,
int level: int ref);
@py_object = @py_cobject | @py_flow_node;
@py_source_element = @py_ast_node | @container;
/* XML Files */
xmlEncoding (unique int id: @file ref, varchar(900) encoding: string ref);
xmlDTDs (unique int id: @xmldtd,
varchar(900) root: string ref,
varchar(900) publicId: string ref,
varchar(900) systemId: string ref,
int fileid: @file ref);
xmlElements (unique int id: @xmlelement,
varchar(900) name: string ref,
int parentid: @xmlparent ref,
int idx: int ref,
int fileid: @file ref);
xmlAttrs (unique int id: @xmlattribute,
int elementid: @xmlelement ref,
varchar(900) name: string ref,
varchar(3600) value: string ref,
int idx: int ref,
int fileid: @file ref);
xmlNs (int id: @xmlnamespace,
varchar(900) prefixName: string ref,
varchar(900) URI: string ref,
int fileid: @file ref);
xmlHasNs (int elementId: @xmlnamespaceable ref,
int nsId: @xmlnamespace ref,
int fileid: @file ref);
xmlComments (unique int id: @xmlcomment,
varchar(3600) text: string ref,
int parentid: @xmlparent ref,
int fileid: @file ref);
xmlChars (unique int id: @xmlcharacters,
varchar(3600) text: string ref,
int parentid: @xmlparent ref,
int idx: int ref,
int isCDATA: int ref,
int fileid: @file ref);
@xmlparent = @file | @xmlelement;
@xmlnamespaceable = @xmlelement | @xmlattribute;
xmllocations(int xmlElement: @xmllocatable ref,
int location: @location_default ref);
@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;

View File

@@ -1,3 +1,22 @@
## 0.0.10
### New Queries
* The query "LDAP query built from user-controlled sources" (`py/ldap-injection`) has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @jorgectf](https://github.com/github/codeql/pull/5443).
* The query "Log Injection" (`py/log-injection`) has been promoted from experimental to the main query pack. Its results will now appear when `security-extended` is used. This query was originally [submitted as an experimental query by @haby0](https://github.com/github/codeql/pull/6182).
## 0.0.9
### Bug Fixes
* The [View AST functionality](https://codeql.github.com/docs/codeql-for-visual-studio-code/exploring-the-structure-of-your-source-code/) no longer prints detailed information about regular expressions, greatly improving performance.
## 0.0.8
### Major Analysis Improvements
* User names and other account information is no longer considered to be sensitive data for the queries `py/clear-text-logging-sensitive-data` and `py/clear-text-storage-sensitive-data`, since this lead to many false positives.
## 0.0.7
## 0.0.6

View File

@@ -4,22 +4,22 @@
<qhelp>
<overview>
<p>If an LDAP query or DN is built using string concatenation or string formatting, and the
components of the concatenation include user input without any proper sanitization, a user
components of the concatenation include user input without any proper sanitization, a user
is likely to be able to run malicious LDAP queries.</p>
</overview>
<recommendation>
<p>If user input must be included in an LDAP query or DN, it should be escaped to
avoid a malicious user providing special characters that change the meaning
of the query. In Python2, user input should be escaped with <code>ldap.dn.escape_dn_chars</code>
or <code>ldap.filter.escape_filter_chars</code>, while in Python3, user input should be escaped with
of the query. In Python2, user input should be escaped with <code>ldap.dn.escape_dn_chars</code>
or <code>ldap.filter.escape_filter_chars</code>, while in Python3, user input should be escaped with
<code>ldap3.utils.dn.escape_rdn</code> or <code>ldap3.utils.conv.escape_filter_chars</code>
depending on the component tainted by the user. A good practice is to escape filter characters
depending on the component tainted by the user. A good practice is to escape filter characters
that could change the meaning of the query (https://tools.ietf.org/search/rfc4515#section-3).</p>
</recommendation>
<example>
<p>In the following examples, the code accepts both <code>username</code> and <code>dc</code> from the user,
<p>In the following examples, the code accepts both <code>username</code> and <code>dc</code> from the user,
which it then uses to build a LDAP query and DN.</p>
<p>The first and the second example uses the unsanitized user input directly
@@ -30,7 +30,7 @@ components, and search for a completely different set of values.</p>
<sample src="examples/example_bad1.py" />
<sample src="examples/example_bad2.py" />
<p>In the third and four example, the input provided by the user is sanitized before it is included in the search filter or DN.
<p>In the third and fourth example, the input provided by the user is sanitized before it is included in the search filter or DN.
This ensures the meaning of the query cannot be changed by a malicious user.</p>
<sample src="examples/example_good1.py" />

View File

@@ -0,0 +1,28 @@
/**
* @name LDAP query built from user-controlled sources
* @description Building an LDAP query from user-controlled sources is vulnerable to insertion of
* malicious LDAP code by the user.
* @kind path-problem
* @problem.severity error
* @security-severity 9.8
* @precision high
* @id py/ldap-injection
* @tags security
* external/cwe/cwe-090
*/
// Determine precision above
import python
import semmle.python.security.dataflow.LdapInjection
import DataFlow::PathGraph
from DataFlow::PathNode source, DataFlow::PathNode sink, string parameterName
where
any(LdapInjection::DnConfiguration dnConfig).hasFlowPath(source, sink) and
parameterName = "DN"
or
any(LdapInjection::FilterConfiguration filterConfig).hasFlowPath(source, sink) and
parameterName = "filter"
select sink.getNode(), source, sink,
"$@ LDAP query parameter (" + parameterName + ") comes from $@.", sink.getNode(), "This",
source.getNode(), "a user-provided value"

Some files were not shown because too many files have changed in this diff Show More