mirror of
https://github.com/github/codeql.git
synced 2025-12-21 03:06:31 +01:00
Merge branch 'main' into repeatedWord
This commit is contained in:
@@ -1,3 +1,20 @@
|
||||
## 0.5.2
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
- The documentation of API graphs (the `API` module) has been expanded, and some of the members predicates of `API::Node`
|
||||
have been renamed as follows:
|
||||
- `getAnImmediateUse` -> `asSource`
|
||||
- `getARhs` -> `asSink`
|
||||
- `getAUse` -> `getAValueReachableFromSource`
|
||||
- `getAValueReachingRhs` -> `getAValueReachingSink`
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Improved modeling of sensitive data sources, so common words like `certain` and `secretary` are no longer considered a certificate and a secret (respectively).
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Change `.getASubclass()` on `API::Node` so it allows to follow subclasses even if the class has a class decorator.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Improved modeling of sensitive data sources, so common words like `certain` and `secretary` are no longer considered a certificate and a secret (respectively).
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
## 0.5.1
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
- The documentation of API graphs (the `API` module) has been expanded, and some of the members predicates of `API::Node`
|
||||
have been renamed as follows:
|
||||
@@ -8,3 +8,7 @@ category: deprecated
|
||||
- `getARhs` -> `asSink`
|
||||
- `getAUse` -> `getAValueReachableFromSource`
|
||||
- `getAValueReachingRhs` -> `getAValueReachingSink`
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Improved modeling of sensitive data sources, so common words like `certain` and `secretary` are no longer considered a certificate and a secret (respectively).
|
||||
1
python/ql/lib/change-notes/released/0.5.2.md
Normal file
1
python/ql/lib/change-notes/released/0.5.2.md
Normal file
@@ -0,0 +1 @@
|
||||
## 0.5.2
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.5.0
|
||||
lastReleaseVersion: 0.5.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/python-all
|
||||
version: 0.5.1-dev
|
||||
version: 0.5.3-dev
|
||||
groups: python
|
||||
dbscheme: semmlecode.python.dbscheme
|
||||
extractor: python
|
||||
|
||||
@@ -680,8 +680,16 @@ module API {
|
||||
or
|
||||
// Subclassing a node
|
||||
lbl = Label::subclass() and
|
||||
exists(DataFlow::Node superclass | pred.flowsTo(superclass) |
|
||||
ref.asExpr().(PY::ClassExpr).getABase() = superclass.asExpr()
|
||||
exists(PY::ClassExpr clsExpr, DataFlow::Node superclass | pred.flowsTo(superclass) |
|
||||
clsExpr.getABase() = superclass.asExpr() and
|
||||
// Potentially a class decorator could do anything, but we assume they are
|
||||
// "benign" and let subclasses edges flow through anyway.
|
||||
// see example in https://github.com/django/django/blob/c2250cfb80e27cdf8d098428824da2800a18cadf/tests/auth_tests/test_views.py#L40-L46
|
||||
(
|
||||
ref.asExpr() = clsExpr
|
||||
or
|
||||
ref.asExpr() = clsExpr.getADecoratorCall()
|
||||
)
|
||||
)
|
||||
or
|
||||
// awaiting
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -527,16 +527,55 @@ class StarPatternElementNode extends Node, TStarPatternElementNode {
|
||||
override Location getLocation() { result = consumer.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a node that controls whether other nodes are evaluated.
|
||||
*
|
||||
* In the base case, this is the last node of `conditionBlock`, and `flipped` is `false`.
|
||||
* This definition accounts for (short circuting) `and`- and `or`-expressions, as the structure
|
||||
* of basic blocks will reflect their semantics.
|
||||
*
|
||||
* However, in the program
|
||||
* ```python
|
||||
* if not is_safe(path):
|
||||
* return
|
||||
* ```
|
||||
* the last node in the `ConditionBlock` is `not is_safe(path)`.
|
||||
*
|
||||
* We would like to consider also `is_safe(path)` a guard node, albeit with `flipped` being `true`.
|
||||
* Thus we recurse through `not`-expressions.
|
||||
*/
|
||||
ControlFlowNode guardNode(ConditionBlock conditionBlock, boolean flipped) {
|
||||
// Base case: the last node truly does determine which successor is chosen
|
||||
result = conditionBlock.getLastNode() and
|
||||
flipped = false
|
||||
or
|
||||
// Recursive case: if a guard node is a `not`-expression,
|
||||
// the operand is also a guard node, but with inverted polarity.
|
||||
exists(UnaryExprNode notNode |
|
||||
result = notNode.getOperand() and
|
||||
notNode.getNode().getOp() instanceof Not
|
||||
|
|
||||
notNode = guardNode(conditionBlock, flipped.booleanNot())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that controls whether other nodes are evaluated.
|
||||
*
|
||||
* The field `flipped` allows us to match `GuardNode`s underneath
|
||||
* `not`-expressions and still choose the appropriate branch.
|
||||
*/
|
||||
class GuardNode extends ControlFlowNode {
|
||||
ConditionBlock conditionBlock;
|
||||
boolean flipped;
|
||||
|
||||
GuardNode() { this = conditionBlock.getLastNode() }
|
||||
GuardNode() { this = guardNode(conditionBlock, flipped) }
|
||||
|
||||
/** Holds if this guard controls block `b` upon evaluating to `branch`. */
|
||||
predicate controlsBlock(BasicBlock b, boolean branch) { conditionBlock.controls(b, branch) }
|
||||
predicate controlsBlock(BasicBlock b, boolean branch) {
|
||||
branch in [true, false] and
|
||||
conditionBlock.controls(b, branch.booleanXor(flipped))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,9 +74,7 @@ private module NotExposed {
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for fullyQualifiedToApiGraphPath */
|
||||
deprecated string fullyQualifiedToAPIGraphPath(string fullyQaulified) {
|
||||
result = fullyQualifiedToApiGraphPath(fullyQaulified)
|
||||
}
|
||||
deprecated predicate fullyQualifiedToAPIGraphPath = fullyQualifiedToApiGraphPath/1;
|
||||
|
||||
bindingset[this]
|
||||
abstract class FindSubclassesSpec extends string {
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
## 0.4.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Contextual queries and the query libraries they depend on have been moved to the `codeql/python-all` package.
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Contextual queries and the query libraries they depend on have been moved to the `codeql/python-all` package.
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
## 0.3.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Contextual queries and the query libraries they depend on have been moved to the `codeql/python-all` package.
|
||||
5
python/ql/src/change-notes/released/0.4.0.md
Normal file
5
python/ql/src/change-notes/released/0.4.0.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.4.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Contextual queries and the query libraries they depend on have been moved to the `codeql/python-all` package.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.2.0
|
||||
lastReleaseVersion: 0.4.0
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
|
||||
blob_client.require_encryption = True
|
||||
blob_client.key_encryption_key = kek
|
||||
# GOOD: Must use `encryption_version` set to `2.0`
|
||||
blob_client.encryption_version = '2.0' # Use Version 2.0!
|
||||
with open("decryptedcontentfile.txt", "rb") as stream:
|
||||
blob_client.upload_blob(stream, overwrite=OVERWRITE_EXISTING)
|
||||
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>Azure Storage .NET, Java, and Python SDKs support encryption on the client with a customer-managed key that is maintained in Azure Key Vault or another key store.</p>
|
||||
<p>Current release versions of the Azure Storage SDKs use cipher block chaining (CBC mode) for client-side encryption (referred to as <code>v1</code>).</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Consider switching to <code>v2</code> client-side encryption.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<sample src="UnsafeUsageOfClientSideEncryptionVersion.py" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
<li>
|
||||
<a href="http://aka.ms/azstorageclientencryptionblog">Azure Storage Client Encryption Blog.</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-30187">CVE-2022-30187</a>
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @name Unsafe usage of v1 version of Azure Storage client-side encryption.
|
||||
* @description Using version v1 of Azure Storage client-side encryption is insecure, and may enable an attacker to decrypt encrypted data
|
||||
* @kind problem
|
||||
* @tags security
|
||||
* cryptography
|
||||
* external/cwe/cwe-327
|
||||
* @id py/azure-storage/unsafe-client-side-encryption-in-use
|
||||
* @problem.severity error
|
||||
* @precision medium
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.ApiGraphs
|
||||
|
||||
predicate isUnsafeClientSideAzureStorageEncryptionViaAttributes(Call call, AttrNode node) {
|
||||
exists(
|
||||
API::Node n, API::Node n2, Attribute a, AssignStmt astmt, API::Node uploadBlob,
|
||||
ControlFlowNode ctrlFlowNode, string s
|
||||
|
|
||||
s in ["key_encryption_key", "key_resolver_function"] and
|
||||
n =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getReturn()
|
||||
.getMember(s) and
|
||||
n2 =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getReturn()
|
||||
.getMember("upload_blob") and
|
||||
n.getAValueReachableFromSource().asExpr() = a and
|
||||
astmt.getATarget() = a and
|
||||
a.getAFlowNode() = node and
|
||||
uploadBlob =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getReturn()
|
||||
.getMember("upload_blob") and
|
||||
uploadBlob.getACall().asExpr() = call and
|
||||
ctrlFlowNode = call.getAFlowNode() and
|
||||
node.strictlyReaches(ctrlFlowNode) and
|
||||
node != ctrlFlowNode and
|
||||
not exists(
|
||||
AssignStmt astmt2, Attribute a2, AttrNode encryptionVersionSet, StrConst uc,
|
||||
API::Node encryptionVersion
|
||||
|
|
||||
uc = astmt2.getValue() and
|
||||
uc.getText() in ["'2.0'", "2.0"] and
|
||||
encryptionVersion =
|
||||
API::moduleImport("azure")
|
||||
.getMember("storage")
|
||||
.getMember("blob")
|
||||
.getMember("BlobClient")
|
||||
.getReturn()
|
||||
.getMember("encryption_version") and
|
||||
encryptionVersion.getAValueReachableFromSource().asExpr() = a2 and
|
||||
astmt2.getATarget() = a2 and
|
||||
a2.getAFlowNode() = encryptionVersionSet and
|
||||
encryptionVersionSet.strictlyReaches(ctrlFlowNode)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isUnsafeClientSideAzureStorageEncryptionViaObjectCreation(Call call, ControlFlowNode node) {
|
||||
exists(API::Node c, string s, Keyword k | k.getAFlowNode() = node |
|
||||
c.getACall().asExpr() = call and
|
||||
c = API::moduleImport("azure").getMember("storage").getMember("blob").getMember(s) and
|
||||
s in ["ContainerClient", "BlobClient", "BlobServiceClient"] and
|
||||
k.getArg() = "key_encryption_key" and
|
||||
k = call.getANamedArg() and
|
||||
not k.getValue() instanceof None and
|
||||
not exists(Keyword k2 | k2 = call.getANamedArg() |
|
||||
k2.getArg() = "encryption_version" and
|
||||
k2.getValue().(StrConst).getText() in ["'2.0'", "2.0"]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from Call call, ControlFlowNode node
|
||||
where
|
||||
isUnsafeClientSideAzureStorageEncryptionViaAttributes(call, node) or
|
||||
isUnsafeClientSideAzureStorageEncryptionViaObjectCreation(call, node)
|
||||
select node, "Unsafe usage of v1 version of Azure Storage client-side encryption."
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/python-queries
|
||||
version: 0.2.1-dev
|
||||
version: 0.4.1-dev
|
||||
groups:
|
||||
- python
|
||||
- queries
|
||||
|
||||
@@ -50,7 +50,7 @@ def test_non_eq2():
|
||||
if not ts == "safe":
|
||||
ensure_tainted(ts) # $ tainted
|
||||
else:
|
||||
ensure_not_tainted(ts) # $ SPURIOUS: tainted
|
||||
ensure_not_tainted(ts)
|
||||
|
||||
|
||||
def test_in_list():
|
||||
@@ -157,7 +157,7 @@ def test_not_in2():
|
||||
if not ts in ["safe", "also_safe"]:
|
||||
ensure_tainted(ts) # $ tainted
|
||||
else:
|
||||
ensure_not_tainted(ts) # $ SPURIOUS: tainted
|
||||
ensure_not_tainted(ts)
|
||||
|
||||
|
||||
def is_safe(x):
|
||||
|
||||
@@ -6,12 +6,20 @@ isSanitizer
|
||||
| TestTaintTrackingConfiguration | test.py:34:39:34:39 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test.py:52:28:52:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test.py:66:10:66:29 | ControlFlowNode for emulated_escaping() |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:30:28:30:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:45:28:45:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:50:28:50:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:89:28:89:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:100:28:100:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:145:28:145:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:33:28:33:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:40:28:40:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:48:28:48:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:53:28:53:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:92:28:92:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:103:28:103:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:111:28:111:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:130:28:130:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:137:28:137:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:148:28:148:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:155:28:155:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:151:28:151:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:158:28:158:28 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:167:24:167:24 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:176:24:176:24 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:185:24:185:24 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_logical.py:193:24:193:24 | ControlFlowNode for s |
|
||||
| TestTaintTrackingConfiguration | test_reference.py:31:28:31:28 | ControlFlowNode for s |
|
||||
|
||||
@@ -6,6 +6,12 @@ predicate isSafeCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean branc
|
||||
branch = true
|
||||
}
|
||||
|
||||
predicate isUnsafeCheck(DataFlow::GuardNode g, ControlFlowNode node, boolean branch) {
|
||||
g.(CallNode).getNode().getFunc().(Name).getId() in ["is_unsafe", "emulated_is_unsafe"] and
|
||||
node = g.(CallNode).getAnArg() and
|
||||
branch = false
|
||||
}
|
||||
|
||||
class CustomSanitizerOverrides extends TestTaintTrackingConfiguration {
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
exists(Call call |
|
||||
@@ -16,6 +22,8 @@ class CustomSanitizerOverrides extends TestTaintTrackingConfiguration {
|
||||
node.asExpr().(Call).getFunc().(Name).getId() = "emulated_escaping"
|
||||
or
|
||||
node = DataFlow::BarrierGuard<isSafeCheck/3>::getABarrierNode()
|
||||
or
|
||||
node = DataFlow::BarrierGuard<isUnsafeCheck/3>::getABarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ def random_choice():
|
||||
def is_safe(arg):
|
||||
return arg == "safe"
|
||||
|
||||
def is_unsafe(arg):
|
||||
return arg == TAINTED_STRING
|
||||
|
||||
|
||||
def test_basic():
|
||||
s = TAINTED_STRING
|
||||
@@ -34,7 +37,7 @@ def test_basic():
|
||||
if not is_safe(s):
|
||||
ensure_tainted(s) # $ tainted
|
||||
else:
|
||||
ensure_not_tainted(s) # $ SPURIOUS: tainted
|
||||
ensure_not_tainted(s)
|
||||
|
||||
|
||||
def test_if_in_depth():
|
||||
@@ -105,7 +108,7 @@ def test_and():
|
||||
ensure_tainted(s) # $ tainted
|
||||
else:
|
||||
# cannot be tainted
|
||||
ensure_not_tainted(s) # $ SPURIOUS: tainted
|
||||
ensure_not_tainted(s)
|
||||
|
||||
|
||||
def test_tricky():
|
||||
@@ -124,14 +127,14 @@ def test_nesting_not():
|
||||
s = TAINTED_STRING
|
||||
|
||||
if not(not(is_safe(s))):
|
||||
ensure_not_tainted(s) # $ SPURIOUS: tainted
|
||||
ensure_not_tainted(s)
|
||||
else:
|
||||
ensure_tainted(s) # $ tainted
|
||||
|
||||
if not(not(not(is_safe(s)))):
|
||||
ensure_tainted(s) # $ tainted
|
||||
else:
|
||||
ensure_not_tainted(s) # $ SPURIOUS: tainted
|
||||
ensure_not_tainted(s)
|
||||
|
||||
|
||||
# Adding `and True` makes the sanitizer trigger when it would otherwise not. See output in
|
||||
@@ -161,7 +164,16 @@ def test_with_return():
|
||||
if not is_safe(s):
|
||||
return
|
||||
|
||||
ensure_not_tainted(s) # $ SPURIOUS: tainted
|
||||
ensure_not_tainted(s)
|
||||
|
||||
|
||||
def test_with_return_neg():
|
||||
s = TAINTED_STRING
|
||||
|
||||
if is_unsafe(s):
|
||||
return
|
||||
|
||||
ensure_not_tainted(s)
|
||||
|
||||
|
||||
def test_with_exception():
|
||||
@@ -170,7 +182,15 @@ def test_with_exception():
|
||||
if not is_safe(s):
|
||||
raise Exception("unsafe")
|
||||
|
||||
ensure_not_tainted(s) # $ SPURIOUS: tainted
|
||||
ensure_not_tainted(s)
|
||||
|
||||
def test_with_exception_neg():
|
||||
s = TAINTED_STRING
|
||||
|
||||
if is_unsafe(s):
|
||||
raise Exception("unsafe")
|
||||
|
||||
ensure_not_tainted(s)
|
||||
|
||||
# Make tests runable
|
||||
|
||||
@@ -182,7 +202,12 @@ test_tricky()
|
||||
test_nesting_not()
|
||||
test_nesting_not_with_and_true()
|
||||
test_with_return()
|
||||
test_with_return_neg()
|
||||
try:
|
||||
test_with_exception()
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
test_with_exception_neg()
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -65,6 +65,9 @@ def to_inner_scope():
|
||||
also_x = foo() # $ MISSING: tracked
|
||||
print(also_x) # $ MISSING: tracked
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Function decorator
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
def my_decorator(func):
|
||||
# This part doesn't make any sense in a normal decorator, but just shows how we
|
||||
@@ -135,7 +138,7 @@ class Bar(Foo):
|
||||
def track_self(self): # $ tracked_self
|
||||
self.meth1() # $ tracked_self
|
||||
super().meth2()
|
||||
super(Bar, self).foo3() # $ tracked_self
|
||||
super(Bar, self).meth3() # $ tracked_self
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Tracking of attribute lookup after "long" import chain
|
||||
|
||||
@@ -16,4 +16,19 @@ def internal():
|
||||
def my_internal_method(self): #$ def=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getMember("my_internal_method")
|
||||
pass
|
||||
|
||||
int_instance = IntMyView() #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getReturn()
|
||||
int_instance = IntMyView() #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getReturn()
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Class decorator
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
def my_class_decorator(cls):
|
||||
print("dummy decorator")
|
||||
return cls
|
||||
|
||||
@my_class_decorator
|
||||
class MyViewWithDecorator(View): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass()
|
||||
pass
|
||||
|
||||
class SubclassFromDecorated(MyViewWithDecorator): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getASubclass()
|
||||
pass
|
||||
|
||||
@@ -7,8 +7,6 @@ edges
|
||||
| tarslip.py:40:7:40:39 | ControlFlowNode for Attribute() | tarslip.py:41:24:41:26 | ControlFlowNode for tar |
|
||||
| tarslip.py:56:7:56:39 | ControlFlowNode for Attribute() | tarslip.py:57:5:57:9 | GSSA Variable entry |
|
||||
| tarslip.py:57:5:57:9 | GSSA Variable entry | tarslip.py:59:21:59:25 | ControlFlowNode for entry |
|
||||
| tarslip.py:79:7:79:39 | ControlFlowNode for Attribute() | tarslip.py:80:5:80:9 | GSSA Variable entry |
|
||||
| tarslip.py:80:5:80:9 | GSSA Variable entry | tarslip.py:82:21:82:25 | ControlFlowNode for entry |
|
||||
nodes
|
||||
| tarslip.py:12:7:12:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| tarslip.py:13:1:13:3 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar |
|
||||
@@ -23,9 +21,6 @@ nodes
|
||||
| tarslip.py:56:7:56:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| tarslip.py:57:5:57:9 | GSSA Variable entry | semmle.label | GSSA Variable entry |
|
||||
| tarslip.py:59:21:59:25 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry |
|
||||
| tarslip.py:79:7:79:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| tarslip.py:80:5:80:9 | GSSA Variable entry | semmle.label | GSSA Variable entry |
|
||||
| tarslip.py:82:21:82:25 | ControlFlowNode for entry | semmle.label | ControlFlowNode for entry |
|
||||
subpaths
|
||||
#select
|
||||
| tarslip.py:13:1:13:3 | ControlFlowNode for tar | tarslip.py:12:7:12:39 | ControlFlowNode for Attribute() | tarslip.py:13:1:13:3 | ControlFlowNode for tar | Extraction of tarfile from $@ | tarslip.py:12:7:12:39 | ControlFlowNode for Attribute() | a potentially untrusted source |
|
||||
@@ -33,4 +28,3 @@ subpaths
|
||||
| tarslip.py:37:17:37:21 | ControlFlowNode for entry | tarslip.py:33:7:33:39 | ControlFlowNode for Attribute() | tarslip.py:37:17:37:21 | ControlFlowNode for entry | Extraction of tarfile from $@ | tarslip.py:33:7:33:39 | ControlFlowNode for Attribute() | a potentially untrusted source |
|
||||
| tarslip.py:41:24:41:26 | ControlFlowNode for tar | tarslip.py:40:7:40:39 | ControlFlowNode for Attribute() | tarslip.py:41:24:41:26 | ControlFlowNode for tar | Extraction of tarfile from $@ | tarslip.py:40:7:40:39 | ControlFlowNode for Attribute() | a potentially untrusted source |
|
||||
| tarslip.py:59:21:59:25 | ControlFlowNode for entry | tarslip.py:56:7:56:39 | ControlFlowNode for Attribute() | tarslip.py:59:21:59:25 | ControlFlowNode for entry | Extraction of tarfile from $@ | tarslip.py:56:7:56:39 | ControlFlowNode for Attribute() | a potentially untrusted source |
|
||||
| tarslip.py:82:21:82:25 | ControlFlowNode for entry | tarslip.py:79:7:79:39 | ControlFlowNode for Attribute() | tarslip.py:82:21:82:25 | ControlFlowNode for entry | Extraction of tarfile from $@ | tarslip.py:79:7:79:39 | ControlFlowNode for Attribute() | a potentially untrusted source |
|
||||
|
||||
Reference in New Issue
Block a user