mirror of
https://github.com/github/codeql.git
synced 2026-05-27 17:41:24 +02:00
Compare commits
10 Commits
refs/heads
...
z80coder/q
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a716d39370 | ||
|
|
335b2466a9 | ||
|
|
96ae9617ec | ||
|
|
82029663b2 | ||
|
|
4cd15ba654 | ||
|
|
c17c10e450 | ||
|
|
a0f479d503 | ||
|
|
24a5e8a8e1 | ||
|
|
427cdf480a | ||
|
|
8e1f2645cb |
3
.github/labeler.yml
vendored
3
.github/labeler.yml
vendored
@@ -26,6 +26,3 @@ documentation:
|
||||
- "**/*.qhelp"
|
||||
- "**/*.md"
|
||||
- docs/**/*
|
||||
|
||||
"QL-for-QL":
|
||||
- ql/**/*
|
||||
1
.github/workflows/check-change-note.yml
vendored
1
.github/workflows/check-change-note.yml
vendored
@@ -7,7 +7,6 @@ on:
|
||||
- "*/ql/src/**/*.ql"
|
||||
- "*/ql/src/**/*.qll"
|
||||
- "!**/experimental/**"
|
||||
- "!ql/**"
|
||||
|
||||
jobs:
|
||||
check-change-note:
|
||||
|
||||
60
.github/workflows/ql-for-ql-build.yml
vendored
60
.github/workflows/ql-for-ql-build.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@erik-krogh/ql
|
||||
uses: github/codeql-action/init@esbena/ql
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- name: Get CodeQL version
|
||||
@@ -56,46 +56,27 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache entire extractor
|
||||
id: cache-extractor
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
ql/target/release/ql-autobuilder
|
||||
ql/target/release/ql-autobuilder.exe
|
||||
ql/target/release/ql-extractor
|
||||
ql/target/release/ql-extractor.exe
|
||||
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||
- name: Cache cargo
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
uses: actions/cache@v2
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
ql/target
|
||||
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Check formatting
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd ql; cargo fmt --all -- --check
|
||||
- name: Build
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd ql; cargo build --verbose
|
||||
- name: Run tests
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd ql; cargo test --verbose
|
||||
- name: Release build
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd ql; cargo build --release
|
||||
- name: Generate dbscheme
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: extractor-ubuntu-latest
|
||||
path: |
|
||||
ql/target/release/ql-autobuilder
|
||||
ql/target/release/ql-autobuilder.exe
|
||||
ql/target/release/ql-extractor
|
||||
ql/target/release/ql-extractor.exe
|
||||
retention-days: 1
|
||||
@@ -120,10 +101,6 @@ jobs:
|
||||
unzip query-pack-zip/*.zip -d pack
|
||||
cp -r ql/codeql-extractor.yml ql/tools ql/ql/src/ql.dbscheme.stats pack/
|
||||
mkdir -p pack/tools/linux64
|
||||
if [[ -f linux64/ql-autobuilder ]]; then
|
||||
cp linux64/ql-autobuilder pack/tools/linux64/autobuilder
|
||||
chmod +x pack/tools/linux64/autobuilder
|
||||
fi
|
||||
if [[ -f linux64/ql-extractor ]]; then
|
||||
cp linux64/ql-extractor pack/tools/linux64/extractor
|
||||
chmod +x pack/tools/linux64/extractor
|
||||
@@ -135,16 +112,13 @@ jobs:
|
||||
name: codeql-ql-pack
|
||||
path: codeql-ql.zip
|
||||
retention-days: 1
|
||||
analyze:
|
||||
analyze:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
folder: [cpp, csharp, java, javascript, python, ql, ruby]
|
||||
|
||||
needs:
|
||||
|
||||
needs:
|
||||
- package
|
||||
|
||||
steps:
|
||||
|
||||
steps:
|
||||
- name: Download pack
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
@@ -166,27 +140,13 @@ jobs:
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Create CodeQL config file
|
||||
run: |
|
||||
echo "paths:" > ${CONF}
|
||||
echo " - ${FOLDER}" >> ${CONF}
|
||||
echo "paths-ignore:" >> ${CONF}
|
||||
echo " - ql/ql/test" >> ${CONF}
|
||||
echo "Config file: "
|
||||
cat ${CONF}
|
||||
env:
|
||||
CONF: ./ql-for-ql-config.yml
|
||||
FOLDER: ${{ matrix.folder }}
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@erik-krogh/ql
|
||||
uses: github/codeql-action/init@esbena/ql
|
||||
with:
|
||||
languages: ql
|
||||
db-location: ${{ runner.temp }}/db
|
||||
config-file: ./ql-for-ql-config.yml
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@erik-krogh/ql
|
||||
with:
|
||||
category: "ql-for-ql-${{ matrix.folder }}"
|
||||
uses: github/codeql-action/analyze@esbena/ql
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@erik-krogh/ql
|
||||
uses: github/codeql-action/init@esbena/ql
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: actions/cache@v2
|
||||
|
||||
6
.github/workflows/ql-for-ql-tests.yml
vendored
6
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -4,11 +4,11 @@ on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "ql/**"
|
||||
- ql/*
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "ql/**"
|
||||
- ql/*
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@erik-krogh/ql
|
||||
uses: github/codeql-action/init@esbena/ql
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: actions/cache@v2
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
lgtm,codescanning
|
||||
* The "Cleartext transmission of sensitive information" (`cpp/cleartext-transmission`) query has been improved, reducing the number of false positive results when encryption is present.
|
||||
@@ -73,7 +73,7 @@ class Options extends string {
|
||||
* __assume(0);
|
||||
* ```
|
||||
* (note that in this case if the hint is wrong and the expression is reached at
|
||||
* runtime, the program's behavior is undefined)
|
||||
* runtime, the program's behaviour is undefined)
|
||||
*/
|
||||
predicate exprExits(Expr e) {
|
||||
e.(AssumeExpr).getChild(0).(CompileTimeConstantInt).getIntValue() = 0 or
|
||||
|
||||
@@ -50,7 +50,7 @@ class CustomOptions extends Options {
|
||||
* __assume(0);
|
||||
* ```
|
||||
* (note that in this case if the hint is wrong and the expression is reached at
|
||||
* runtime, the program's behavior is undefined)
|
||||
* runtime, the program's behaviour is undefined)
|
||||
*/
|
||||
override predicate exprExits(Expr e) { Options.super.exprExits(e) }
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* `Instruction` level), and then using the array length analysis and the range
|
||||
* analysis together to prove that some of these pointer dereferences are safe.
|
||||
*
|
||||
* The analysis is soundy, i.e. it is sound if no undefined behavior is present
|
||||
* The analysis is soundy, i.e. it is sound if no undefined behaviour is present
|
||||
* in the program.
|
||||
* Furthermore, it crucially depends on the soundiness of the range analysis and
|
||||
* the array length analysis.
|
||||
|
||||
@@ -153,11 +153,9 @@ library class SSAHelper extends int {
|
||||
* Modern Compiler Implementation by Andrew Appel.
|
||||
*/
|
||||
private predicate frontier_phi_node(StackVariable v, BasicBlock b) {
|
||||
exists(BasicBlock x |
|
||||
dominanceFrontier(x, b) and ssa_defn_rec(pragma[only_bind_into](v), pragma[only_bind_into](x))
|
||||
) and
|
||||
exists(BasicBlock x | dominanceFrontier(x, b) and ssa_defn_rec(v, x)) and
|
||||
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
||||
live_at_start_of_bb(pragma[only_bind_into](v), b)
|
||||
live_at_start_of_bb(v, b)
|
||||
}
|
||||
|
||||
private predicate ssa_defn_rec(StackVariable v, BasicBlock b) {
|
||||
|
||||
@@ -15,23 +15,11 @@ module Consistency {
|
||||
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||
string toString() { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
|
||||
predicate uniqueEnclosingCallableExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
|
||||
predicate uniqueNodeLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
|
||||
predicate missingLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||
predicate postWithInFlowExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
|
||||
predicate reverseReadExclude(Node n) { none() }
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
@@ -58,7 +46,6 @@ module Consistency {
|
||||
n instanceof RelevantNode and
|
||||
c = count(nodeGetEnclosingCallable(n)) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
|
||||
msg = "Node should have one enclosing callable but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -79,7 +66,6 @@ module Consistency {
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
|
||||
msg = "Node should have one location but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -90,8 +76,7 @@ module Consistency {
|
||||
strictcount(Node n |
|
||||
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
|
||||
)
|
||||
) and
|
||||
msg = "Nodes without location: " + c
|
||||
)
|
||||
@@ -187,7 +172,6 @@ module Consistency {
|
||||
|
||||
query predicate reverseRead(Node n, string msg) {
|
||||
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
||||
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ class LambdaCapture extends Locatable, @lambdacapture {
|
||||
* An identifier is captured by reference if:
|
||||
* - It is explicitly captured by reference.
|
||||
* - It is implicitly captured, and the lambda's default capture mode is by-reference.
|
||||
* - The identifier is "this". [Said behavior is dictated by the C++11 standard, but it
|
||||
* - The identifier is "this". [Said behaviour is dictated by the C++11 standard, but it
|
||||
* is actually "*this" being captured rather than "this".]
|
||||
*/
|
||||
predicate isCapturedByReference() { lambda_capture(this, _, _, _, true, _, _) }
|
||||
|
||||
@@ -15,23 +15,11 @@ module Consistency {
|
||||
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||
string toString() { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
|
||||
predicate uniqueEnclosingCallableExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
|
||||
predicate uniqueNodeLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
|
||||
predicate missingLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||
predicate postWithInFlowExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
|
||||
predicate reverseReadExclude(Node n) { none() }
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
@@ -58,7 +46,6 @@ module Consistency {
|
||||
n instanceof RelevantNode and
|
||||
c = count(nodeGetEnclosingCallable(n)) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
|
||||
msg = "Node should have one enclosing callable but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -79,7 +66,6 @@ module Consistency {
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
|
||||
msg = "Node should have one location but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -90,8 +76,7 @@ module Consistency {
|
||||
strictcount(Node n |
|
||||
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
|
||||
)
|
||||
) and
|
||||
msg = "Nodes without location: " + c
|
||||
)
|
||||
@@ -187,7 +172,6 @@ module Consistency {
|
||||
|
||||
query predicate reverseRead(Node n, string msg) {
|
||||
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
||||
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>The return value of a call to <code>snprintf</code> is the number of characters that <i>would have</i> been written to the buffer assuming there was sufficient space. In the event that the operation reaches the end of the buffer and more than one character is discarded, the return value will be greater than the buffer size. This can cause incorrect behavior, for example:
|
||||
<p>The return value of a call to <code>snprintf</code> is the number of characters that <i>would have</i> been written to the buffer assuming there was sufficient space. In the event that the operation reaches the end of the buffer and more than one character is discarded, the return value will be greater than the buffer size. This can cause incorrect behaviour, for example:
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
|
||||
@@ -14,188 +14,105 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.security.SensitiveExprs
|
||||
import semmle.code.cpp.dataflow.TaintTracking
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* A DataFlow node corresponding to a variable or function call that
|
||||
* might contain or return a password or other sensitive information.
|
||||
*/
|
||||
class SensitiveNode extends DataFlow::Node {
|
||||
SensitiveNode() {
|
||||
this.asExpr() = any(SensitiveVariable sv).getInitializer().getExpr() or
|
||||
this.asExpr().(VariableAccess).getTarget() =
|
||||
any(SensitiveVariable sv).(GlobalOrNamespaceVariable) or
|
||||
this.asUninitialized() instanceof SensitiveVariable or
|
||||
this.asParameter() instanceof SensitiveVariable or
|
||||
this.asExpr().(FunctionCall).getTarget() instanceof SensitiveFunction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that sends or receives data over a network.
|
||||
*/
|
||||
abstract class SendRecv extends Function {
|
||||
/**
|
||||
* Gets the expression for the socket or similar object used for sending or
|
||||
* receiving data through the function call `call` (if any).
|
||||
*/
|
||||
abstract Expr getSocketExpr(Call call);
|
||||
|
||||
/**
|
||||
* Gets the expression for the buffer to be sent from / received into through
|
||||
* the function call `call`.
|
||||
*/
|
||||
abstract Expr getDataExpr(Call call);
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that sends data over a network.
|
||||
*/
|
||||
class Send extends SendRecv instanceof RemoteFlowSinkFunction {
|
||||
override Expr getSocketExpr(Call call) {
|
||||
call.getTarget() = this and
|
||||
exists(FunctionInput input, int arg |
|
||||
super.hasSocketInput(input) and
|
||||
input.isParameter(arg) and
|
||||
result = call.getArgument(arg)
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getDataExpr(Call call) {
|
||||
call.getTarget() = this and
|
||||
exists(FunctionInput input, int arg |
|
||||
super.hasRemoteFlowSink(input, _) and
|
||||
input.isParameterDeref(arg) and
|
||||
result = call.getArgument(arg)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that receives data over a network.
|
||||
*/
|
||||
class Recv extends SendRecv instanceof RemoteFlowSourceFunction {
|
||||
override Expr getSocketExpr(Call call) {
|
||||
call.getTarget() = this and
|
||||
exists(FunctionInput input, int arg |
|
||||
super.hasSocketInput(input) and
|
||||
input.isParameter(arg) and
|
||||
result = call.getArgument(arg)
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getDataExpr(Call call) {
|
||||
call.getTarget() = this and
|
||||
exists(FunctionOutput output, int arg |
|
||||
super.hasRemoteFlowSource(output, _) and
|
||||
output.isParameterDeref(arg) and
|
||||
result = call.getArgument(arg)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function call that sends or receives data over a network.
|
||||
*
|
||||
* note: function calls such as `write` may be writing to a network source
|
||||
* or a file. We could attempt to determine which, and sort results into
|
||||
* `cpp/cleartext-transmission` and perhaps `cpp/cleartext-storage-file`. In
|
||||
* practice it usually isn't very important which query reports a result as
|
||||
* long as its reported exactly once.
|
||||
*
|
||||
* We do exclude function calls that specify a constant socket, which is
|
||||
* likely to mean standard input, standard output or a similar channel.
|
||||
*/
|
||||
abstract class NetworkSendRecv extends FunctionCall {
|
||||
SendRecv target;
|
||||
/**
|
||||
* Gets the expression for the socket or similar object used for sending or
|
||||
* receiving data (if any).
|
||||
*/
|
||||
abstract Expr getSocketExpr();
|
||||
|
||||
NetworkSendRecv() {
|
||||
this.getTarget() = target and
|
||||
// exclude calls based on the socket...
|
||||
not exists(GVN g |
|
||||
g = globalValueNumber(target.getSocketExpr(this)) and
|
||||
(
|
||||
// literal constant
|
||||
globalValueNumber(any(Literal l)) = g
|
||||
or
|
||||
// variable (such as a global) initialized to a literal constant
|
||||
exists(Variable v |
|
||||
v.getInitializer().getExpr() instanceof Literal and
|
||||
g = globalValueNumber(v.getAnAccess())
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final Expr getDataExpr() { result = target.getDataExpr(this) }
|
||||
/**
|
||||
* Gets the expression for the buffer to be sent from / received into.
|
||||
*/
|
||||
abstract Expr getDataExpr();
|
||||
}
|
||||
|
||||
/**
|
||||
* A function call that sends data over a network.
|
||||
*
|
||||
* note: functions such as `write` may be writing to a network source or a file. We could attempt to determine which, and sort results into `cpp/cleartext-transmission` and perhaps `cpp/cleartext-storage-file`. In practice it usually isn't very important which query reports a result as long as its reported exactly once.
|
||||
*/
|
||||
class NetworkSend extends NetworkSendRecv {
|
||||
override Send target;
|
||||
RemoteFlowSinkFunction target;
|
||||
|
||||
NetworkSend() { target = this.getTarget() }
|
||||
|
||||
override Expr getSocketExpr() {
|
||||
exists(FunctionInput input, int arg |
|
||||
target.hasSocketInput(input) and
|
||||
input.isParameter(arg) and
|
||||
result = this.getArgument(arg)
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getDataExpr() {
|
||||
exists(FunctionInput input, int arg |
|
||||
target.hasRemoteFlowSink(input, _) and
|
||||
input.isParameterDeref(arg) and
|
||||
result = this.getArgument(arg)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function call that receives data over a network.
|
||||
*/
|
||||
class NetworkRecv extends NetworkSendRecv {
|
||||
override Recv target;
|
||||
}
|
||||
RemoteFlowSourceFunction target;
|
||||
|
||||
/**
|
||||
* An expression that is an argument or return value from an encryption or
|
||||
* decryption call.
|
||||
*/
|
||||
class Encrypted extends Expr {
|
||||
Encrypted() {
|
||||
exists(FunctionCall fc |
|
||||
fc.getTarget().getName().toLowerCase().regexpMatch(".*(crypt|encode|decode).*") and
|
||||
(
|
||||
this = fc or
|
||||
this = fc.getAnArgument()
|
||||
)
|
||||
NetworkRecv() { target = this.getTarget() }
|
||||
|
||||
override Expr getSocketExpr() {
|
||||
exists(FunctionInput input, int arg |
|
||||
target.hasSocketInput(input) and
|
||||
input.isParameter(arg) and
|
||||
result = this.getArgument(arg)
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getDataExpr() {
|
||||
exists(FunctionOutput output, int arg |
|
||||
target.hasRemoteFlowSource(output, _) and
|
||||
output.isParameterDeref(arg) and
|
||||
result = this.getArgument(arg)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint flow from a sensitive expression.
|
||||
* Taint flow from a sensitive expression to a network operation with data
|
||||
* tainted by that expression.
|
||||
*/
|
||||
class FromSensitiveConfiguration extends TaintTracking::Configuration {
|
||||
FromSensitiveConfiguration() { this = "FromSensitiveConfiguration" }
|
||||
class SensitiveSendRecvConfiguration extends TaintTracking::Configuration {
|
||||
SensitiveSendRecvConfiguration() { this = "SensitiveSendRecvConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof SensitiveNode }
|
||||
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveExpr }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(NetworkSendRecv nsr).getDataExpr()
|
||||
or
|
||||
sink.asExpr() instanceof Encrypted
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// flow through encryption functions to the return value (in case we can reach other sinks)
|
||||
node2.asExpr().(Encrypted).(FunctionCall).getAnArgument() = node1.asExpr()
|
||||
exists(NetworkSendRecv transmission |
|
||||
sink.asExpr() = transmission.getDataExpr() and
|
||||
// a zero socket descriptor is standard input, which is not interesting for this query.
|
||||
not exists(Zero zero |
|
||||
DataFlow::localFlow(DataFlow::exprNode(zero),
|
||||
DataFlow::exprNode(transmission.getSocketExpr()))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
FromSensitiveConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
NetworkSendRecv networkSendRecv, string msg
|
||||
SensitiveSendRecvConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
NetworkSendRecv transmission, string msg
|
||||
where
|
||||
// flow from sensitive -> network data
|
||||
config.hasFlowPath(source, sink) and
|
||||
sink.getNode().asExpr() = networkSendRecv.getDataExpr() and
|
||||
// no flow from sensitive -> evidence of encryption
|
||||
not exists(DataFlow::Node encrypted |
|
||||
config.hasFlow(source.getNode(), encrypted) and
|
||||
encrypted.asExpr() instanceof Encrypted
|
||||
) and
|
||||
// construct result
|
||||
if networkSendRecv instanceof NetworkSend
|
||||
sink.getNode().asExpr() = transmission.getDataExpr() and
|
||||
if transmission instanceof NetworkSend
|
||||
then
|
||||
msg =
|
||||
"This operation transmits '" + sink.toString() +
|
||||
@@ -204,4 +121,4 @@ where
|
||||
msg =
|
||||
"This operation receives into '" + sink.toString() +
|
||||
"', which may put unencrypted sensitive data into $@"
|
||||
select networkSendRecv, source, sink, msg, source, source.getNode().toString()
|
||||
select transmission, source, sink, msg, source, source.getNode().asExpr().toString()
|
||||
|
||||
@@ -1,228 +1,49 @@
|
||||
edges
|
||||
| test3.cpp:17:28:17:36 | password1 | test3.cpp:22:15:22:23 | password1 |
|
||||
| test3.cpp:17:51:17:59 | password2 | test3.cpp:26:15:26:23 | password2 |
|
||||
| test3.cpp:45:8:45:15 | password | test3.cpp:47:15:47:22 | password |
|
||||
| test3.cpp:53:8:53:15 | password | test3.cpp:55:15:55:22 | password |
|
||||
| test3.cpp:71:32:71:40 | password1 | test3.cpp:76:15:76:17 | ptr |
|
||||
| test3.cpp:80:8:80:15 | password | test3.cpp:83:15:83:17 | ptr |
|
||||
| test3.cpp:98:8:98:15 | password | test3.cpp:101:12:101:19 | password |
|
||||
| test3.cpp:112:20:112:25 | buffer | test3.cpp:114:14:114:19 | buffer |
|
||||
| test3.cpp:117:28:117:33 | buffer | test3.cpp:119:9:119:14 | buffer |
|
||||
| test3.cpp:126:9:126:23 | global_password | test3.cpp:144:16:144:29 | call to get_global_str |
|
||||
| test3.cpp:129:39:129:47 | password1 | test3.cpp:138:24:138:32 | password1 |
|
||||
| test3.cpp:132:8:132:15 | password | test3.cpp:134:11:134:18 | password |
|
||||
| test3.cpp:134:11:134:18 | password | test3.cpp:112:20:112:25 | buffer |
|
||||
| test3.cpp:138:21:138:22 | call to id | test3.cpp:140:15:140:17 | ptr |
|
||||
| test3.cpp:138:24:138:32 | password1 | test3.cpp:117:28:117:33 | buffer |
|
||||
| test3.cpp:138:24:138:32 | password1 | test3.cpp:138:21:138:22 | call to id |
|
||||
| test3.cpp:144:16:144:29 | call to get_global_str | test3.cpp:146:15:146:18 | data |
|
||||
| test3.cpp:152:29:152:36 | password | test3.cpp:159:15:159:20 | buffer |
|
||||
| test3.cpp:171:8:171:15 | password | test3.cpp:173:15:173:22 | password |
|
||||
| test3.cpp:171:8:171:15 | password | test3.cpp:175:3:175:17 | call to decrypt_inplace |
|
||||
| test3.cpp:171:8:171:15 | password | test3.cpp:175:19:175:26 | password |
|
||||
| test3.cpp:179:8:179:15 | password | test3.cpp:181:15:181:22 | password |
|
||||
| test3.cpp:179:8:179:15 | password | test3.cpp:184:3:184:17 | call to decrypt_inplace |
|
||||
| test3.cpp:179:8:179:15 | password | test3.cpp:184:19:184:26 | password |
|
||||
| test3.cpp:188:8:188:15 | password | test3.cpp:191:15:191:22 | password |
|
||||
| test3.cpp:188:8:188:15 | password | test3.cpp:193:18:193:28 | call to rtn_decrypt |
|
||||
| test3.cpp:188:8:188:15 | password | test3.cpp:193:30:193:37 | password |
|
||||
| test3.cpp:197:8:197:15 | password | test3.cpp:199:3:199:17 | call to encrypt_inplace |
|
||||
| test3.cpp:197:8:197:15 | password | test3.cpp:199:19:199:26 | password |
|
||||
| test3.cpp:197:8:197:15 | password | test3.cpp:201:15:201:22 | password |
|
||||
| test3.cpp:205:8:205:15 | password | test3.cpp:207:3:207:17 | call to encrypt_inplace |
|
||||
| test3.cpp:205:8:205:15 | password | test3.cpp:207:19:207:26 | password |
|
||||
| test3.cpp:205:8:205:15 | password | test3.cpp:210:15:210:22 | password |
|
||||
| test3.cpp:214:8:214:15 | password | test3.cpp:217:18:217:28 | call to rtn_encrypt |
|
||||
| test3.cpp:214:8:214:15 | password | test3.cpp:217:18:217:28 | call to rtn_encrypt |
|
||||
| test3.cpp:214:8:214:15 | password | test3.cpp:217:30:217:37 | password |
|
||||
| test3.cpp:214:8:214:15 | password | test3.cpp:219:15:219:26 | password_ptr |
|
||||
| test3.cpp:217:18:217:28 | call to rtn_encrypt | test3.cpp:219:15:219:26 | password_ptr |
|
||||
| test3.cpp:225:34:225:41 | password | test3.cpp:227:22:227:29 | password |
|
||||
| test3.cpp:225:34:225:41 | password | test3.cpp:228:26:228:33 | password |
|
||||
| test3.cpp:239:7:239:14 | password | test3.cpp:241:8:241:15 | password |
|
||||
| test3.cpp:239:7:239:14 | password | test3.cpp:242:8:242:15 | password |
|
||||
| test3.cpp:252:8:252:16 | password1 | test3.cpp:254:15:254:23 | password1 |
|
||||
| test3.cpp:252:8:252:16 | password1 | test3.cpp:256:3:256:19 | call to decrypt_to_buffer |
|
||||
| test3.cpp:252:8:252:16 | password1 | test3.cpp:256:21:256:29 | password1 |
|
||||
| test3.cpp:252:24:252:32 | password2 | test3.cpp:256:3:256:19 | call to decrypt_to_buffer |
|
||||
| test3.cpp:252:24:252:32 | password2 | test3.cpp:256:32:256:40 | password2 |
|
||||
| test3.cpp:260:8:260:16 | password1 | test3.cpp:262:3:262:19 | call to encrypt_to_buffer |
|
||||
| test3.cpp:260:8:260:16 | password1 | test3.cpp:262:21:262:29 | password1 |
|
||||
| test3.cpp:260:24:260:32 | password2 | test3.cpp:262:3:262:19 | call to encrypt_to_buffer |
|
||||
| test3.cpp:260:24:260:32 | password2 | test3.cpp:262:32:262:40 | password2 |
|
||||
| test3.cpp:260:24:260:32 | password2 | test3.cpp:264:15:264:23 | password2 |
|
||||
| test3.cpp:268:19:268:26 | password | test3.cpp:272:15:272:18 | data |
|
||||
| test3.cpp:278:20:278:23 | data | test3.cpp:278:20:278:23 | data |
|
||||
| test3.cpp:278:20:278:23 | data | test3.cpp:280:14:280:17 | data |
|
||||
| test3.cpp:283:20:283:23 | data | test3.cpp:283:20:283:23 | data |
|
||||
| test3.cpp:283:20:283:23 | data | test3.cpp:285:14:285:17 | data |
|
||||
| test3.cpp:288:20:288:23 | data | test3.cpp:290:14:290:17 | data |
|
||||
| test3.cpp:293:20:293:23 | data | test3.cpp:293:20:293:23 | data |
|
||||
| test3.cpp:293:20:293:23 | data | test3.cpp:295:14:295:17 | data |
|
||||
| test3.cpp:298:20:298:23 | data | test3.cpp:300:14:300:17 | data |
|
||||
| test3.cpp:308:41:308:49 | password1 | test3.cpp:312:3:312:17 | call to encrypt_inplace |
|
||||
| test3.cpp:308:41:308:49 | password1 | test3.cpp:312:19:312:27 | password1 |
|
||||
| test3.cpp:308:41:308:49 | password1 | test3.cpp:313:11:313:19 | password1 |
|
||||
| test3.cpp:308:41:308:49 | password1 | test3.cpp:314:11:314:19 | password1 |
|
||||
| test3.cpp:308:41:308:49 | password1 | test3.cpp:316:11:316:19 | password1 |
|
||||
| test3.cpp:308:41:308:49 | password1 | test3.cpp:317:11:317:19 | password1 |
|
||||
| test3.cpp:308:58:308:66 | password2 | test3.cpp:324:11:324:14 | data |
|
||||
| test3.cpp:308:58:308:66 | password2 | test3.cpp:325:11:325:14 | data |
|
||||
| test3.cpp:313:11:313:19 | password1 | test3.cpp:278:20:278:23 | data |
|
||||
| test3.cpp:313:11:313:19 | password1 | test3.cpp:313:11:313:19 | ref arg password1 |
|
||||
| test3.cpp:313:11:313:19 | ref arg password1 | test3.cpp:314:11:314:19 | password1 |
|
||||
| test3.cpp:314:11:314:19 | password1 | test3.cpp:283:20:283:23 | data |
|
||||
| test3.cpp:316:11:316:19 | password1 | test3.cpp:283:20:283:23 | data |
|
||||
| test3.cpp:316:11:316:19 | password1 | test3.cpp:316:11:316:19 | ref arg password1 |
|
||||
| test3.cpp:316:11:316:19 | ref arg password1 | test3.cpp:317:11:317:19 | password1 |
|
||||
| test3.cpp:317:11:317:19 | password1 | test3.cpp:288:20:288:23 | data |
|
||||
| test3.cpp:324:11:324:14 | data | test3.cpp:293:20:293:23 | data |
|
||||
| test3.cpp:324:11:324:14 | data | test3.cpp:324:11:324:14 | ref arg data |
|
||||
| test3.cpp:324:11:324:14 | ref arg data | test3.cpp:325:11:325:14 | data |
|
||||
| test3.cpp:325:11:325:14 | data | test3.cpp:298:20:298:23 | data |
|
||||
| test3.cpp:339:9:339:16 | password | test3.cpp:341:16:341:23 | password |
|
||||
| test3.cpp:350:9:350:16 | password | test3.cpp:352:16:352:23 | password |
|
||||
| test3.cpp:350:9:350:16 | password | test3.cpp:353:4:353:18 | call to decrypt_inplace |
|
||||
| test3.cpp:350:9:350:16 | password | test3.cpp:353:20:353:27 | password |
|
||||
| test.cpp:41:23:41:43 | cleartext password! | test.cpp:48:21:48:27 | call to encrypt |
|
||||
| test.cpp:41:23:41:43 | cleartext password! | test.cpp:48:29:48:39 | thePassword |
|
||||
| test.cpp:66:23:66:43 | cleartext password! | test.cpp:76:21:76:27 | call to encrypt |
|
||||
| test.cpp:66:23:66:43 | cleartext password! | test.cpp:76:29:76:39 | thePassword |
|
||||
| test3.cpp:68:21:68:29 | password1 | test3.cpp:70:15:70:17 | ptr |
|
||||
| test3.cpp:75:15:75:22 | password | test3.cpp:77:15:77:17 | ptr |
|
||||
| test3.cpp:106:20:106:25 | buffer | test3.cpp:108:14:108:19 | buffer |
|
||||
| test3.cpp:111:28:111:33 | buffer | test3.cpp:113:9:113:14 | buffer |
|
||||
| test3.cpp:120:9:120:23 | global_password | test3.cpp:138:16:138:29 | call to get_global_str |
|
||||
| test3.cpp:128:11:128:18 | password | test3.cpp:106:20:106:25 | buffer |
|
||||
| test3.cpp:132:21:132:22 | call to id | test3.cpp:134:15:134:17 | ptr |
|
||||
| test3.cpp:132:24:132:32 | password1 | test3.cpp:111:28:111:33 | buffer |
|
||||
| test3.cpp:132:24:132:32 | password1 | test3.cpp:132:21:132:22 | call to id |
|
||||
| test3.cpp:138:16:138:29 | call to get_global_str | test3.cpp:140:15:140:18 | data |
|
||||
| test3.cpp:151:19:151:26 | password | test3.cpp:153:15:153:20 | buffer |
|
||||
nodes
|
||||
| test3.cpp:17:28:17:36 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:17:51:17:59 | password2 | semmle.label | password2 |
|
||||
| test3.cpp:22:15:22:23 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:26:15:26:23 | password2 | semmle.label | password2 |
|
||||
| test3.cpp:45:8:45:15 | password | semmle.label | password |
|
||||
| test3.cpp:47:15:47:22 | password | semmle.label | password |
|
||||
| test3.cpp:53:8:53:15 | password | semmle.label | password |
|
||||
| test3.cpp:55:15:55:22 | password | semmle.label | password |
|
||||
| test3.cpp:71:32:71:40 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:76:15:76:17 | ptr | semmle.label | ptr |
|
||||
| test3.cpp:80:8:80:15 | password | semmle.label | password |
|
||||
| test3.cpp:83:15:83:17 | ptr | semmle.label | ptr |
|
||||
| test3.cpp:98:8:98:15 | password | semmle.label | password |
|
||||
| test3.cpp:101:12:101:19 | password | semmle.label | password |
|
||||
| test3.cpp:112:20:112:25 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:114:14:114:19 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:117:28:117:33 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:119:9:119:14 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:126:9:126:23 | global_password | semmle.label | global_password |
|
||||
| test3.cpp:129:39:129:47 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:132:8:132:15 | password | semmle.label | password |
|
||||
| test3.cpp:134:11:134:18 | password | semmle.label | password |
|
||||
| test3.cpp:138:21:138:22 | call to id | semmle.label | call to id |
|
||||
| test3.cpp:138:24:138:32 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:140:15:140:17 | ptr | semmle.label | ptr |
|
||||
| test3.cpp:144:16:144:29 | call to get_global_str | semmle.label | call to get_global_str |
|
||||
| test3.cpp:146:15:146:18 | data | semmle.label | data |
|
||||
| test3.cpp:152:29:152:36 | password | semmle.label | password |
|
||||
| test3.cpp:159:15:159:20 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:171:8:171:15 | password | semmle.label | password |
|
||||
| test3.cpp:173:15:173:22 | password | semmle.label | password |
|
||||
| test3.cpp:175:3:175:17 | call to decrypt_inplace | semmle.label | call to decrypt_inplace |
|
||||
| test3.cpp:175:19:175:26 | password | semmle.label | password |
|
||||
| test3.cpp:179:8:179:15 | password | semmle.label | password |
|
||||
| test3.cpp:181:15:181:22 | password | semmle.label | password |
|
||||
| test3.cpp:184:3:184:17 | call to decrypt_inplace | semmle.label | call to decrypt_inplace |
|
||||
| test3.cpp:184:19:184:26 | password | semmle.label | password |
|
||||
| test3.cpp:188:8:188:15 | password | semmle.label | password |
|
||||
| test3.cpp:191:15:191:22 | password | semmle.label | password |
|
||||
| test3.cpp:193:18:193:28 | call to rtn_decrypt | semmle.label | call to rtn_decrypt |
|
||||
| test3.cpp:193:30:193:37 | password | semmle.label | password |
|
||||
| test3.cpp:197:8:197:15 | password | semmle.label | password |
|
||||
| test3.cpp:199:3:199:17 | call to encrypt_inplace | semmle.label | call to encrypt_inplace |
|
||||
| test3.cpp:199:19:199:26 | password | semmle.label | password |
|
||||
| test3.cpp:201:15:201:22 | password | semmle.label | password |
|
||||
| test3.cpp:205:8:205:15 | password | semmle.label | password |
|
||||
| test3.cpp:207:3:207:17 | call to encrypt_inplace | semmle.label | call to encrypt_inplace |
|
||||
| test3.cpp:207:19:207:26 | password | semmle.label | password |
|
||||
| test3.cpp:210:15:210:22 | password | semmle.label | password |
|
||||
| test3.cpp:214:8:214:15 | password | semmle.label | password |
|
||||
| test3.cpp:217:18:217:28 | call to rtn_encrypt | semmle.label | call to rtn_encrypt |
|
||||
| test3.cpp:217:18:217:28 | call to rtn_encrypt | semmle.label | call to rtn_encrypt |
|
||||
| test3.cpp:217:30:217:37 | password | semmle.label | password |
|
||||
| test3.cpp:219:15:219:26 | password_ptr | semmle.label | password_ptr |
|
||||
| test3.cpp:225:34:225:41 | password | semmle.label | password |
|
||||
| test3.cpp:227:22:227:29 | password | semmle.label | password |
|
||||
| test3.cpp:228:26:228:33 | password | semmle.label | password |
|
||||
| test3.cpp:239:7:239:14 | password | semmle.label | password |
|
||||
| test3.cpp:241:8:241:15 | password | semmle.label | password |
|
||||
| test3.cpp:242:8:242:15 | password | semmle.label | password |
|
||||
| test3.cpp:252:8:252:16 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:252:24:252:32 | password2 | semmle.label | password2 |
|
||||
| test3.cpp:254:15:254:23 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:256:3:256:19 | call to decrypt_to_buffer | semmle.label | call to decrypt_to_buffer |
|
||||
| test3.cpp:256:21:256:29 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:256:32:256:40 | password2 | semmle.label | password2 |
|
||||
| test3.cpp:260:8:260:16 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:260:24:260:32 | password2 | semmle.label | password2 |
|
||||
| test3.cpp:262:3:262:19 | call to encrypt_to_buffer | semmle.label | call to encrypt_to_buffer |
|
||||
| test3.cpp:262:21:262:29 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:262:32:262:40 | password2 | semmle.label | password2 |
|
||||
| test3.cpp:264:15:264:23 | password2 | semmle.label | password2 |
|
||||
| test3.cpp:268:19:268:26 | password | semmle.label | password |
|
||||
| test3.cpp:272:15:272:18 | data | semmle.label | data |
|
||||
| test3.cpp:278:20:278:23 | data | semmle.label | data |
|
||||
| test3.cpp:278:20:278:23 | data | semmle.label | data |
|
||||
| test3.cpp:280:14:280:17 | data | semmle.label | data |
|
||||
| test3.cpp:283:20:283:23 | data | semmle.label | data |
|
||||
| test3.cpp:283:20:283:23 | data | semmle.label | data |
|
||||
| test3.cpp:285:14:285:17 | data | semmle.label | data |
|
||||
| test3.cpp:288:20:288:23 | data | semmle.label | data |
|
||||
| test3.cpp:290:14:290:17 | data | semmle.label | data |
|
||||
| test3.cpp:293:20:293:23 | data | semmle.label | data |
|
||||
| test3.cpp:293:20:293:23 | data | semmle.label | data |
|
||||
| test3.cpp:295:14:295:17 | data | semmle.label | data |
|
||||
| test3.cpp:298:20:298:23 | data | semmle.label | data |
|
||||
| test3.cpp:300:14:300:17 | data | semmle.label | data |
|
||||
| test3.cpp:308:41:308:49 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:308:58:308:66 | password2 | semmle.label | password2 |
|
||||
| test3.cpp:312:3:312:17 | call to encrypt_inplace | semmle.label | call to encrypt_inplace |
|
||||
| test3.cpp:312:19:312:27 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:313:11:313:19 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:313:11:313:19 | ref arg password1 | semmle.label | ref arg password1 |
|
||||
| test3.cpp:314:11:314:19 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:316:11:316:19 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:316:11:316:19 | ref arg password1 | semmle.label | ref arg password1 |
|
||||
| test3.cpp:317:11:317:19 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:324:11:324:14 | data | semmle.label | data |
|
||||
| test3.cpp:324:11:324:14 | ref arg data | semmle.label | ref arg data |
|
||||
| test3.cpp:325:11:325:14 | data | semmle.label | data |
|
||||
| test3.cpp:339:9:339:16 | password | semmle.label | password |
|
||||
| test3.cpp:341:16:341:23 | password | semmle.label | password |
|
||||
| test3.cpp:350:9:350:16 | password | semmle.label | password |
|
||||
| test3.cpp:352:16:352:23 | password | semmle.label | password |
|
||||
| test3.cpp:353:4:353:18 | call to decrypt_inplace | semmle.label | call to decrypt_inplace |
|
||||
| test3.cpp:353:20:353:27 | password | semmle.label | password |
|
||||
| test.cpp:41:23:41:43 | cleartext password! | semmle.label | cleartext password! |
|
||||
| test.cpp:48:21:48:27 | call to encrypt | semmle.label | call to encrypt |
|
||||
| test.cpp:48:29:48:39 | thePassword | semmle.label | thePassword |
|
||||
| test.cpp:66:23:66:43 | cleartext password! | semmle.label | cleartext password! |
|
||||
| test.cpp:76:21:76:27 | call to encrypt | semmle.label | call to encrypt |
|
||||
| test.cpp:76:29:76:39 | thePassword | semmle.label | thePassword |
|
||||
| test3.cpp:20:15:20:23 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:24:15:24:23 | password2 | semmle.label | password2 |
|
||||
| test3.cpp:41:15:41:22 | password | semmle.label | password |
|
||||
| test3.cpp:49:15:49:22 | password | semmle.label | password |
|
||||
| test3.cpp:68:21:68:29 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:70:15:70:17 | ptr | semmle.label | ptr |
|
||||
| test3.cpp:75:15:75:22 | password | semmle.label | password |
|
||||
| test3.cpp:77:15:77:17 | ptr | semmle.label | ptr |
|
||||
| test3.cpp:95:12:95:19 | password | semmle.label | password |
|
||||
| test3.cpp:106:20:106:25 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:108:14:108:19 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:111:28:111:33 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:113:9:113:14 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:120:9:120:23 | global_password | semmle.label | global_password |
|
||||
| test3.cpp:128:11:128:18 | password | semmle.label | password |
|
||||
| test3.cpp:132:21:132:22 | call to id | semmle.label | call to id |
|
||||
| test3.cpp:132:24:132:32 | password1 | semmle.label | password1 |
|
||||
| test3.cpp:134:15:134:17 | ptr | semmle.label | ptr |
|
||||
| test3.cpp:138:16:138:29 | call to get_global_str | semmle.label | call to get_global_str |
|
||||
| test3.cpp:140:15:140:18 | data | semmle.label | data |
|
||||
| test3.cpp:151:19:151:26 | password | semmle.label | password |
|
||||
| test3.cpp:153:15:153:20 | buffer | semmle.label | buffer |
|
||||
subpaths
|
||||
| test3.cpp:138:24:138:32 | password1 | test3.cpp:117:28:117:33 | buffer | test3.cpp:119:9:119:14 | buffer | test3.cpp:138:21:138:22 | call to id |
|
||||
| test3.cpp:313:11:313:19 | password1 | test3.cpp:278:20:278:23 | data | test3.cpp:278:20:278:23 | data | test3.cpp:313:11:313:19 | ref arg password1 |
|
||||
| test3.cpp:316:11:316:19 | password1 | test3.cpp:283:20:283:23 | data | test3.cpp:283:20:283:23 | data | test3.cpp:316:11:316:19 | ref arg password1 |
|
||||
| test3.cpp:324:11:324:14 | data | test3.cpp:293:20:293:23 | data | test3.cpp:293:20:293:23 | data | test3.cpp:324:11:324:14 | ref arg data |
|
||||
| test3.cpp:132:24:132:32 | password1 | test3.cpp:111:28:111:33 | buffer | test3.cpp:113:9:113:14 | buffer | test3.cpp:132:21:132:22 | call to id |
|
||||
#select
|
||||
| test3.cpp:22:3:22:6 | call to send | test3.cpp:17:28:17:36 | password1 | test3.cpp:22:15:22:23 | password1 | This operation transmits 'password1', which may contain unencrypted sensitive data from $@ | test3.cpp:17:28:17:36 | password1 | password1 |
|
||||
| test3.cpp:26:3:26:6 | call to send | test3.cpp:17:51:17:59 | password2 | test3.cpp:26:15:26:23 | password2 | This operation transmits 'password2', which may contain unencrypted sensitive data from $@ | test3.cpp:17:51:17:59 | password2 | password2 |
|
||||
| test3.cpp:47:3:47:6 | call to recv | test3.cpp:45:8:45:15 | password | test3.cpp:47:15:47:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:45:8:45:15 | password | password |
|
||||
| test3.cpp:55:3:55:6 | call to recv | test3.cpp:53:8:53:15 | password | test3.cpp:55:15:55:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:53:8:53:15 | password | password |
|
||||
| test3.cpp:76:3:76:6 | call to send | test3.cpp:71:32:71:40 | password1 | test3.cpp:76:15:76:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:71:32:71:40 | password1 | password1 |
|
||||
| test3.cpp:83:3:83:6 | call to recv | test3.cpp:80:8:80:15 | password | test3.cpp:83:15:83:17 | ptr | This operation receives into 'ptr', which may put unencrypted sensitive data into $@ | test3.cpp:80:8:80:15 | password | password |
|
||||
| test3.cpp:101:3:101:6 | call to read | test3.cpp:98:8:98:15 | password | test3.cpp:101:12:101:19 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:98:8:98:15 | password | password |
|
||||
| test3.cpp:114:2:114:5 | call to recv | test3.cpp:132:8:132:15 | password | test3.cpp:114:14:114:19 | buffer | This operation receives into 'buffer', which may put unencrypted sensitive data into $@ | test3.cpp:132:8:132:15 | password | password |
|
||||
| test3.cpp:140:3:140:6 | call to send | test3.cpp:129:39:129:47 | password1 | test3.cpp:140:15:140:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:129:39:129:47 | password1 | password1 |
|
||||
| test3.cpp:146:3:146:6 | call to send | test3.cpp:126:9:126:23 | global_password | test3.cpp:146:15:146:18 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:126:9:126:23 | global_password | global_password |
|
||||
| test3.cpp:159:3:159:6 | call to send | test3.cpp:152:29:152:36 | password | test3.cpp:159:15:159:20 | buffer | This operation transmits 'buffer', which may contain unencrypted sensitive data from $@ | test3.cpp:152:29:152:36 | password | password |
|
||||
| test3.cpp:227:2:227:5 | call to send | test3.cpp:225:34:225:41 | password | test3.cpp:227:22:227:29 | password | This operation transmits 'password', which may contain unencrypted sensitive data from $@ | test3.cpp:225:34:225:41 | password | password |
|
||||
| test3.cpp:228:2:228:5 | call to send | test3.cpp:225:34:225:41 | password | test3.cpp:228:26:228:33 | password | This operation transmits 'password', which may contain unencrypted sensitive data from $@ | test3.cpp:225:34:225:41 | password | password |
|
||||
| test3.cpp:241:2:241:6 | call to fgets | test3.cpp:239:7:239:14 | password | test3.cpp:241:8:241:15 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:239:7:239:14 | password | password |
|
||||
| test3.cpp:242:2:242:6 | call to fgets | test3.cpp:239:7:239:14 | password | test3.cpp:242:8:242:15 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:239:7:239:14 | password | password |
|
||||
| test3.cpp:272:3:272:6 | call to send | test3.cpp:268:19:268:26 | password | test3.cpp:272:15:272:18 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:268:19:268:26 | password | password |
|
||||
| test3.cpp:295:2:295:5 | call to send | test3.cpp:308:58:308:66 | password2 | test3.cpp:295:14:295:17 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:308:58:308:66 | password2 | password2 |
|
||||
| test3.cpp:300:2:300:5 | call to send | test3.cpp:308:58:308:66 | password2 | test3.cpp:300:14:300:17 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:308:58:308:66 | password2 | password2 |
|
||||
| test3.cpp:341:4:341:7 | call to recv | test3.cpp:339:9:339:16 | password | test3.cpp:341:16:341:23 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:339:9:339:16 | password | password |
|
||||
| test3.cpp:20:3:20:6 | call to send | test3.cpp:20:15:20:23 | password1 | test3.cpp:20:15:20:23 | password1 | This operation transmits 'password1', which may contain unencrypted sensitive data from $@ | test3.cpp:20:15:20:23 | password1 | password1 |
|
||||
| test3.cpp:24:3:24:6 | call to send | test3.cpp:24:15:24:23 | password2 | test3.cpp:24:15:24:23 | password2 | This operation transmits 'password2', which may contain unencrypted sensitive data from $@ | test3.cpp:24:15:24:23 | password2 | password2 |
|
||||
| test3.cpp:41:3:41:6 | call to recv | test3.cpp:41:15:41:22 | password | test3.cpp:41:15:41:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:41:15:41:22 | password | password |
|
||||
| test3.cpp:49:3:49:6 | call to recv | test3.cpp:49:15:49:22 | password | test3.cpp:49:15:49:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:49:15:49:22 | password | password |
|
||||
| test3.cpp:70:3:70:6 | call to send | test3.cpp:68:21:68:29 | password1 | test3.cpp:70:15:70:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:68:21:68:29 | password1 | password1 |
|
||||
| test3.cpp:77:3:77:6 | call to recv | test3.cpp:75:15:75:22 | password | test3.cpp:77:15:77:17 | ptr | This operation receives into 'ptr', which may put unencrypted sensitive data into $@ | test3.cpp:75:15:75:22 | password | password |
|
||||
| test3.cpp:95:3:95:6 | call to read | test3.cpp:95:12:95:19 | password | test3.cpp:95:12:95:19 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:95:12:95:19 | password | password |
|
||||
| test3.cpp:108:2:108:5 | call to recv | test3.cpp:128:11:128:18 | password | test3.cpp:108:14:108:19 | buffer | This operation receives into 'buffer', which may put unencrypted sensitive data into $@ | test3.cpp:128:11:128:18 | password | password |
|
||||
| test3.cpp:134:3:134:6 | call to send | test3.cpp:132:24:132:32 | password1 | test3.cpp:134:15:134:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:132:24:132:32 | password1 | password1 |
|
||||
| test3.cpp:140:3:140:6 | call to send | test3.cpp:120:9:120:23 | global_password | test3.cpp:140:15:140:18 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:120:9:120:23 | global_password | global_password |
|
||||
| test3.cpp:153:3:153:6 | call to send | test3.cpp:151:19:151:26 | password | test3.cpp:153:15:153:20 | buffer | This operation transmits 'buffer', which may contain unencrypted sensitive data from $@ | test3.cpp:151:19:151:26 | password | password |
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
typedef unsigned long size_t;
|
||||
#define STDIN_FILENO (0)
|
||||
#define STDOUT_FILENO (1)
|
||||
int stdout_fileno = STDOUT_FILENO;
|
||||
|
||||
size_t strlen(const char *s);
|
||||
|
||||
@@ -33,10 +31,6 @@ void test_send(const char *password1, const char *password2, const char *passwor
|
||||
{
|
||||
send(val(), message, strlen(message), val()); // GOOD: `message` is not a password
|
||||
}
|
||||
|
||||
{
|
||||
send(stdout_fileno, password2, strlen(password2), val()); // GOOD: `password2` is sent to stdout, not a network socket (this may be an issue but is not within the scope of the `cpp/cleartext-transmission` query)
|
||||
}
|
||||
}
|
||||
|
||||
void test_receive()
|
||||
@@ -131,7 +125,7 @@ void test_interprocedural(const char *password1)
|
||||
{
|
||||
char password[256];
|
||||
|
||||
my_recv(password, 256); // BAD: `password` is received plaintext [detected in `my_recv`]
|
||||
my_recv(password, 256); // BAD: `password` is received plaintext [detected on line 108]
|
||||
}
|
||||
|
||||
{
|
||||
@@ -159,200 +153,3 @@ void test_taint(const char *password)
|
||||
send(val(), buffer, 16, val()); // BAD: `password` is (partially) sent plaintext
|
||||
}
|
||||
}
|
||||
|
||||
void encrypt_inplace(char *buffer);
|
||||
void decrypt_inplace(char *buffer);
|
||||
char *rtn_encrypt(const char *buffer);
|
||||
char *rtn_decrypt(const char *buffer);
|
||||
|
||||
void test_decrypt()
|
||||
{
|
||||
{
|
||||
char password[256];
|
||||
|
||||
recv(val(), password, 256, val()); // GOOD: password is encrypted
|
||||
|
||||
decrypt_inplace(password); // proof that `password` was in fact encrypted
|
||||
}
|
||||
|
||||
{
|
||||
char password[256];
|
||||
|
||||
recv(val(), password, 256, val()); // GOOD: password is encrypted
|
||||
password[255] = 0;
|
||||
|
||||
decrypt_inplace(password); // proof that `password` was in fact encrypted
|
||||
}
|
||||
|
||||
{
|
||||
char password[256];
|
||||
char *password_ptr;
|
||||
|
||||
recv(val(), password, 256, val()); // GOOD: password is encrypted
|
||||
|
||||
password_ptr = rtn_decrypt(password); // proof that `password` was in fact encrypted
|
||||
}
|
||||
|
||||
{
|
||||
char password[256];
|
||||
|
||||
encrypt_inplace(password); // proof that `password` is in fact encrypted
|
||||
|
||||
send(val(), password, strlen(password), val()); // GOOD: password is encrypted
|
||||
}
|
||||
|
||||
{
|
||||
char password[256];
|
||||
|
||||
encrypt_inplace(password); // proof that `password` is in fact encrypted
|
||||
password[255] = 0;
|
||||
|
||||
send(val(), password, strlen(password), val()); // GOOD: password is encrypted
|
||||
}
|
||||
|
||||
{
|
||||
char password[256];
|
||||
char *password_ptr;
|
||||
|
||||
password_ptr = rtn_encrypt(password); // proof that `password` is in fact encrypted
|
||||
|
||||
send(val(), password_ptr, strlen(password_ptr), val()); // GOOD: password is encrypted
|
||||
}
|
||||
}
|
||||
|
||||
int get_socket(int from);
|
||||
|
||||
void test_more_stdio(const char *password)
|
||||
{
|
||||
send(get_socket(1), password, 128, val()); // GOOD: `getsocket(1)` is probably standard output [FALSE POSITIVE]
|
||||
send(get_socket(val()), password, 128, val()); // BAD
|
||||
}
|
||||
|
||||
typedef struct {} FILE;
|
||||
char *fgets(char *s, int n, FILE *stream);
|
||||
|
||||
FILE *get_stdstream(int index);
|
||||
#define STDIN_STREAM (get_stdstream(0))
|
||||
|
||||
void test_fgets(FILE *stream)
|
||||
{
|
||||
char password[128];
|
||||
|
||||
fgets(password, 128, stream); // BAD
|
||||
fgets(password, 128, STDIN_STREAM); // GOOD: `STDIN_STREAM` is probably standard input [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void encrypt_to_buffer(const char *input, char* output);
|
||||
void decrypt_to_buffer(const char *input, char* output);
|
||||
char *strcpy(char *s1, const char *s2);
|
||||
|
||||
void test_crypt_more()
|
||||
{
|
||||
{
|
||||
char password1[256], password2[256];
|
||||
|
||||
recv(val(), password1, 256, val()); // GOOD: password is encrypted
|
||||
|
||||
decrypt_to_buffer(password1, password2); // proof that `password1` was in fact encrypted
|
||||
}
|
||||
|
||||
{
|
||||
char password1[256], password2[256];
|
||||
|
||||
encrypt_to_buffer(password1, password2); // proof that `password2` is in fact encrypted
|
||||
|
||||
send(val(), password2, strlen(password2), val()); // GOOD: password is encrypted
|
||||
}
|
||||
|
||||
{
|
||||
char data[256], password[256];
|
||||
|
||||
strcpy(data, password); // not proof of anything
|
||||
|
||||
send(val(), data, strlen(data), val()); // BAD: password is sent plaintext
|
||||
}
|
||||
}
|
||||
|
||||
bool cond();
|
||||
|
||||
void target1(char *data)
|
||||
{
|
||||
send(val(), data, strlen(data), val()); // GOOD: encrypted
|
||||
}
|
||||
|
||||
void target2(char *data)
|
||||
{
|
||||
send(val(), data, strlen(data), val()); // BAD: from one source this is a plaintext password [NOT DETECTED]
|
||||
}
|
||||
|
||||
void target3(char *data)
|
||||
{
|
||||
send(val(), data, strlen(data), val()); // BAD: data is a plaintext password [NOT DETECTED]
|
||||
}
|
||||
|
||||
void target4(char *data)
|
||||
{
|
||||
send(val(), data, strlen(data), val()); // BAD: data is a plaintext password
|
||||
}
|
||||
|
||||
void target5(char *data)
|
||||
{
|
||||
send(val(), data, strlen(data), val()); // BAD: from one source this is a plaintext password
|
||||
}
|
||||
|
||||
void target6(char *data)
|
||||
{
|
||||
send(val(), data, strlen(data), val()); // GOOD: not a password
|
||||
}
|
||||
|
||||
void test_multiple_sources_source(char *password1, char *password2)
|
||||
{
|
||||
if (cond())
|
||||
{
|
||||
encrypt_inplace(password1);
|
||||
target1(password1);
|
||||
target2(password1);
|
||||
} else {
|
||||
target2(password1);
|
||||
target3(password1);
|
||||
}
|
||||
|
||||
if (cond())
|
||||
{
|
||||
char *data = password2;
|
||||
|
||||
target4(data);
|
||||
target5(data);
|
||||
} else {
|
||||
char *data = "harmless";
|
||||
|
||||
target5(data);
|
||||
target6(data);
|
||||
}
|
||||
}
|
||||
|
||||
void test_loops()
|
||||
{
|
||||
{
|
||||
while (cond())
|
||||
{
|
||||
char password[256];
|
||||
|
||||
recv(val(), password, 256, val()); // BAD: not encrypted
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
while (cond())
|
||||
{
|
||||
char password[256];
|
||||
|
||||
recv(val(), password, 256, val()); // GOOD: password is encrypted
|
||||
decrypt_inplace(password); // proof that `password` was in fact encrypted
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
import csharp
|
||||
import cil
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowPublic
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowImplConsistency::Consistency
|
||||
|
||||
private class MyConsistencyConfiguration extends ConsistencyConfiguration {
|
||||
override predicate uniqueEnclosingCallableExclude(Node n) {
|
||||
// TODO: Remove once static initializers are folded into the
|
||||
// static constructors
|
||||
exists(ControlFlow::Node cfn |
|
||||
cfn.getElement() = any(FieldOrProperty f | f.isStatic()).getAChild+() and
|
||||
cfn = n.getControlFlowNode()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate uniqueNodeLocationExclude(Node n) {
|
||||
// Methods with multiple implementations
|
||||
n instanceof ParameterNode
|
||||
or
|
||||
this.missingLocationExclude(n)
|
||||
}
|
||||
|
||||
override predicate missingLocationExclude(Node n) {
|
||||
// Some CIL methods are missing locations
|
||||
n.asParameter() instanceof CIL::Parameter
|
||||
}
|
||||
|
||||
override predicate postWithInFlowExclude(Node n) {
|
||||
n instanceof SummaryNode
|
||||
or
|
||||
n.asExpr().(ObjectCreation).hasInitializer()
|
||||
}
|
||||
|
||||
override predicate argHasPostUpdateExclude(ArgumentNode n) {
|
||||
n instanceof SummaryNode
|
||||
or
|
||||
n.asExpr().(Expr).stripCasts().getType() =
|
||||
any(Type t |
|
||||
not t instanceof RefType and
|
||||
not t = any(TypeParameter tp | not tp.isValueType())
|
||||
or
|
||||
t instanceof NullType
|
||||
)
|
||||
or
|
||||
n instanceof ImplicitCapturedArgumentNode
|
||||
or
|
||||
n instanceof ParamsArgumentNode
|
||||
or
|
||||
n.asExpr() instanceof CIL::Expr
|
||||
}
|
||||
|
||||
override predicate reverseReadExclude(Node n) { n.asExpr() = any(AwaitExpr ae).getExpr() }
|
||||
}
|
||||
@@ -89,7 +89,7 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
|
||||
|
||||
override Location getLocation() { result = Element.super.getLocation() }
|
||||
|
||||
override Location getALocation() { cil_method_location(this.getUnboundMethod+(), result) }
|
||||
override Location getALocation() { cil_method_location(this.getUnboundDeclaration(), result) }
|
||||
|
||||
override MethodParameter getParameter(int n) {
|
||||
if this.isStatic()
|
||||
|
||||
@@ -80,8 +80,7 @@ module Gvn {
|
||||
LeafType() {
|
||||
not this instanceof GenericType and
|
||||
not this instanceof TypeParameter and
|
||||
not this instanceof DynamicType and
|
||||
not this instanceof TupleType
|
||||
not this instanceof DynamicType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,8 +478,6 @@ module Gvn {
|
||||
GvnType getGlobalValueNumber(Type t) {
|
||||
result = TLeafGvnType(t)
|
||||
or
|
||||
result = TLeafGvnType(t.(TupleType).getUnderlyingType())
|
||||
or
|
||||
t instanceof DynamicType and
|
||||
result = TLeafGvnType(any(ObjectType ot))
|
||||
or
|
||||
|
||||
@@ -585,7 +585,7 @@ class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
sink = getDelegateFlowSinkArg(m, 1, 1) and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
source = getDelegateFlowSourceArg(m, 1) and
|
||||
source = TCallableFlowSourceDelegateArg(1) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::empty()
|
||||
@@ -603,7 +603,7 @@ class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
sink = getDelegateFlowSinkArg(m, 2, 0) and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
source = getDelegateFlowSourceArg(m, 2) and
|
||||
source = TCallableFlowSourceDelegateArg(2) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::empty()
|
||||
@@ -621,12 +621,12 @@ class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
sink = getDelegateFlowSinkArg(m, 2, 0) and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
source = getDelegateFlowSourceArg(m, 2) and
|
||||
source = TCallableFlowSourceDelegateArg(2) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = getDelegateFlowSinkArg(m, 3, 0) and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
source = getDelegateFlowSourceArg(m, 3) and
|
||||
source = TCallableFlowSourceDelegateArg(3) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::empty()
|
||||
@@ -841,7 +841,7 @@ class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
sink = getDelegateFlowSinkArg(m, 4, 1) and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
source = getDelegateFlowSourceArg(m, 4) and
|
||||
source = TCallableFlowSourceDelegateArg(4) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::element()
|
||||
@@ -924,7 +924,7 @@ class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
sink = getDelegateFlowSinkArg(m, 1, 0) and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
source = getDelegateFlowSourceArg(m, 1) and
|
||||
source = TCallableFlowSourceDelegateArg(1) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::element()
|
||||
@@ -943,12 +943,12 @@ class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
sink = getDelegateFlowSinkArg(m, 2, 0) and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
source = getDelegateFlowSourceArg(m, 1) and
|
||||
source = TCallableFlowSourceDelegateArg(1) and
|
||||
sourceAp = AccessPath::element() and
|
||||
sink = getDelegateFlowSinkArg(m, 2, 1) and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
source = getDelegateFlowSourceArg(m, 2) and
|
||||
source = TCallableFlowSourceDelegateArg(2) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::element()
|
||||
|
||||
@@ -15,23 +15,11 @@ module Consistency {
|
||||
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||
string toString() { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
|
||||
predicate uniqueEnclosingCallableExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
|
||||
predicate uniqueNodeLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
|
||||
predicate missingLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||
predicate postWithInFlowExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
|
||||
predicate reverseReadExclude(Node n) { none() }
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
@@ -58,7 +46,6 @@ module Consistency {
|
||||
n instanceof RelevantNode and
|
||||
c = count(nodeGetEnclosingCallable(n)) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
|
||||
msg = "Node should have one enclosing callable but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -79,7 +66,6 @@ module Consistency {
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
|
||||
msg = "Node should have one location but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -90,8 +76,7 @@ module Consistency {
|
||||
strictcount(Node n |
|
||||
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
|
||||
)
|
||||
) and
|
||||
msg = "Nodes without location: " + c
|
||||
)
|
||||
@@ -187,7 +172,6 @@ module Consistency {
|
||||
|
||||
query predicate reverseRead(Node n, string msg) {
|
||||
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
||||
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
|
||||
@@ -65,9 +65,7 @@ abstract class NodeImpl extends Node {
|
||||
|
||||
private class ExprNodeImpl extends ExprNode, NodeImpl {
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result = this.getExpr().(CIL::Expr).getEnclosingCallable()
|
||||
or
|
||||
result = this.getControlFlowNodeImpl().getEnclosingCallable()
|
||||
result = this.getExpr().getEnclosingCallable()
|
||||
}
|
||||
|
||||
override DotNet::Type getTypeImpl() {
|
||||
@@ -620,7 +618,6 @@ private predicate arrayRead(Expr e1, ArrayRead e2) { e1 = e2.getQualifier() }
|
||||
private Type getCSharpType(DotNet::Type t) {
|
||||
result = t
|
||||
or
|
||||
not t instanceof Type and
|
||||
result.matchesHandle(t)
|
||||
}
|
||||
|
||||
@@ -691,7 +688,7 @@ private module Cached {
|
||||
not def.(Ssa::ExplicitDefinition).getADefinition() instanceof
|
||||
AssignableDefinitions::ImplicitParameterDefinition
|
||||
} or
|
||||
TExplicitParameterNode(DotNet::Parameter p) { p = any(DataFlowCallable c).getAParameter() } or
|
||||
TExplicitParameterNode(DotNet::Parameter p) { p.isUnboundDeclaration() } or
|
||||
TInstanceParameterNode(Callable c) {
|
||||
c.isUnboundDeclaration() and not c.(Modifiable).isStatic()
|
||||
} or
|
||||
@@ -710,28 +707,25 @@ private module Cached {
|
||||
TObjectInitializerNode(ControlFlow::Nodes::ElementNode cfn) {
|
||||
cfn.getElement().(ObjectCreation).hasInitializer()
|
||||
} or
|
||||
TExprPostUpdateNode(ControlFlow::Nodes::ExprNode cfn) {
|
||||
exists(Expr e | e = cfn.getExpr() |
|
||||
exists(Type t | t = e.(Argument).stripCasts().getType() |
|
||||
t instanceof RefType and
|
||||
not t instanceof NullType
|
||||
or
|
||||
t = any(TypeParameter tp | not tp.isValueType())
|
||||
)
|
||||
TExprPostUpdateNode(ControlFlow::Nodes::ElementNode cfn) {
|
||||
exists(Argument a, Type t |
|
||||
a = cfn.getElement() and
|
||||
t = a.stripCasts().getType()
|
||||
|
|
||||
t instanceof RefType and
|
||||
not t instanceof NullType
|
||||
or
|
||||
fieldOrPropertyStore(_, _, _, e, true)
|
||||
or
|
||||
arrayStore(_, _, e, true)
|
||||
or
|
||||
// needed for reverse stores; e.g. `x.f1.f2 = y` induces
|
||||
// a store step of `f1` into `x`
|
||||
exists(TExprPostUpdateNode upd, Expr read |
|
||||
upd = TExprPostUpdateNode(read.getAControlFlowNode())
|
||||
|
|
||||
fieldOrPropertyRead(e, _, read)
|
||||
or
|
||||
arrayRead(e, read)
|
||||
)
|
||||
t = any(TypeParameter tp | not tp.isValueType())
|
||||
)
|
||||
or
|
||||
fieldOrPropertyStore(_, _, _, cfn.getElement(), true)
|
||||
or
|
||||
arrayStore(_, _, cfn.getElement(), true)
|
||||
or
|
||||
exists(TExprPostUpdateNode upd, FieldOrPropertyAccess fla |
|
||||
upd = TExprPostUpdateNode(fla.getAControlFlowNode())
|
||||
|
|
||||
cfn.getElement() = fla.getQualifier()
|
||||
)
|
||||
} or
|
||||
TSummaryNode(FlowSummary::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
|
||||
@@ -1442,7 +1436,7 @@ private module OutNodes {
|
||||
import OutNodes
|
||||
|
||||
/** A data-flow node used to model flow summaries. */
|
||||
class SummaryNode extends NodeImpl, TSummaryNode {
|
||||
private class SummaryNode extends NodeImpl, TSummaryNode {
|
||||
private FlowSummary::SummarizedCallable c;
|
||||
private FlowSummaryImpl::Private::SummaryNodeState state;
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ class ExponentialRegexDataflow extends DataFlow2::Configuration {
|
||||
|
||||
/**
|
||||
* An expression passed as the `input` to a call to a `Regex` method, where the regex appears to
|
||||
* have exponential behavior.
|
||||
* have exponential behaviour.
|
||||
*/
|
||||
class ExponentialRegexSink extends DataFlow::ExprNode, Sink {
|
||||
ExponentialRegexSink() {
|
||||
|
||||
@@ -20,7 +20,7 @@ class Parameter extends Variable, @dotnet_parameter {
|
||||
/** Gets the position of this parameter, excluding the `this` parameter. */
|
||||
int getPosition() { this = this.getDeclaringElement().getParameter(result) }
|
||||
|
||||
/** Gets the callable defining this parameter, if any. */
|
||||
/** Gets the callable defining this parameter. */
|
||||
Callable getCallable() { result = this.getDeclaringElement() }
|
||||
|
||||
/** Gets the declaring `Parameterizable`. */
|
||||
|
||||
@@ -171,7 +171,6 @@ Python built-in support
|
||||
Twisted, Web framework
|
||||
Flask-Admin, Web framework
|
||||
starlette, Asynchronous Server Gateway Interface (ASGI)
|
||||
requests, HTTP client
|
||||
dill, Serialization
|
||||
PyYAML, Serialization
|
||||
ruamel.yaml, Serialization
|
||||
|
||||
@@ -130,7 +130,7 @@ private class NumberTaintPreservingCallable extends TaintPreservingCallable {
|
||||
* included in this type however, then a tainted `Container` would imply that its `field` is also
|
||||
* tainted (but not vice versa).
|
||||
*
|
||||
* Note that `TaintTracking::Configuration` applies this behavior by default to array, collection,
|
||||
* Note that `TaintTracking::Configuration` applies this behaviour by default to array, collection,
|
||||
* map-key and map-value content, so that e.g. a tainted `Map` is assumed to have tainted keys and values.
|
||||
*/
|
||||
abstract class TaintInheritingContent extends DataFlow::Content { }
|
||||
|
||||
@@ -15,23 +15,11 @@ module Consistency {
|
||||
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||
string toString() { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
|
||||
predicate uniqueEnclosingCallableExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
|
||||
predicate uniqueNodeLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
|
||||
predicate missingLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||
predicate postWithInFlowExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
|
||||
predicate reverseReadExclude(Node n) { none() }
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
@@ -58,7 +46,6 @@ module Consistency {
|
||||
n instanceof RelevantNode and
|
||||
c = count(nodeGetEnclosingCallable(n)) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
|
||||
msg = "Node should have one enclosing callable but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -79,7 +66,6 @@ module Consistency {
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
|
||||
msg = "Node should have one location but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -90,8 +76,7 @@ module Consistency {
|
||||
strictcount(Node n |
|
||||
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
|
||||
)
|
||||
) and
|
||||
msg = "Nodes without location: " + c
|
||||
)
|
||||
@@ -187,7 +172,6 @@ module Consistency {
|
||||
|
||||
query predicate reverseRead(Node n, string msg) {
|
||||
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
||||
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ SupportMethod getASupportMethod() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CSV specification of the taint-/value-propagation behavior of a test support method (`get` or `newWith` method).
|
||||
* Returns a CSV specification of the taint-/value-propagation behaviour of a test support method (`get` or `newWith` method).
|
||||
*/
|
||||
query string getASupportMethodModel() { result = getASupportMethod().getCsvModel() }
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
lgtm,codescanning
|
||||
* Support for handlebars templates has improved. Raw interpolation tags of the form `{{& ... }}` are now recognized,
|
||||
as well as whitespace-trimming tags like `{{~ ... }}`.
|
||||
@@ -43,7 +43,7 @@ public class Main {
|
||||
* A version identifier that should be updated every time the extractor changes in such a way that
|
||||
* it may produce different tuples for the same file under the same {@link ExtractorConfig}.
|
||||
*/
|
||||
public static final String EXTRACTOR_VERSION = "2021-12-17";
|
||||
public static final String EXTRACTOR_VERSION = "2021-11-23";
|
||||
|
||||
public static final Pattern NEWLINE = Pattern.compile("\n");
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import com.semmle.util.locations.Position;
|
||||
import com.semmle.util.trap.TrapWriter.Label;
|
||||
|
||||
public class TemplateEngines {
|
||||
private static final String MUSTACHE_TAG_TRIPLE = "\\{\\{\\{[~]?(.*?)[~]?\\}\\}\\}"; // {{{ x }}}
|
||||
private static final String MUSTACHE_TAG_DOUBLE = "\\{\\{(?!\\{)[~&]?(.*?)[~]?\\}\\}"; // {{ x }}}
|
||||
private static final String MUSTACHE_TAG_TRIPLE = "\\{\\{\\{(.*?)\\}\\}\\}"; // {{{ x }}}
|
||||
private static final String MUSTACHE_TAG_DOUBLE = "\\{\\{(?!\\{)(.*?)\\}\\}"; // {{ x }}}
|
||||
private static final String MUSTACHE_TAG_PERCENT = "\\{%(?!>)(.*?)%\\}"; // {% x %}
|
||||
private static final String EJS_TAG = "<%(?![%<>}])[-=]?(.*?)[_-]?%>"; // <% x %>
|
||||
|
||||
@@ -22,7 +22,7 @@ public class TemplateEngines {
|
||||
public static final Pattern TEMPLATE_TAGS =
|
||||
Pattern.compile(
|
||||
StringUtil.glue(
|
||||
"|", MUSTACHE_TAG_DOUBLE, MUSTACHE_TAG_TRIPLE, MUSTACHE_TAG_PERCENT, EJS_TAG),
|
||||
"|", TemplateEngines.MUSTACHE_TAG_DOUBLE, MUSTACHE_TAG_TRIPLE, MUSTACHE_TAG_PERCENT, EJS_TAG),
|
||||
Pattern.DOTALL);
|
||||
|
||||
/**
|
||||
|
||||
@@ -178,7 +178,7 @@ module Raw {
|
||||
|
||||
/**
|
||||
* Returns a generated name for the entity. This name is generated such that
|
||||
* entities with the same names have similar behavior.
|
||||
* entities with the same names have similar behaviour.
|
||||
*/
|
||||
private string getApproximateNameForEntity(Entity entity) {
|
||||
count(raw::DataFlow::CallNode call, int index | entityUsedAsArgumentToCall(entity, call, index)) =
|
||||
|
||||
@@ -283,7 +283,7 @@ private module AccessPaths {
|
||||
}
|
||||
|
||||
/** Get a name of a supported generic token-based feature. */
|
||||
private string getASupportedFeatureName() {
|
||||
string getASupportedFeatureName() {
|
||||
result =
|
||||
[
|
||||
"enclosingFunctionName", "calleeName", "receiverName", "argumentIndex", "calleeApiName",
|
||||
@@ -300,12 +300,5 @@ private string getASupportedFeatureName() {
|
||||
predicate tokenFeatures(DataFlow::Node endpoint, string featureName, string featureValue) {
|
||||
// Performance optimization: Restrict feature extraction to endpoints we've explicitly asked to featurize.
|
||||
endpoint = any(FeaturizationConfig cfg).getAnEndpointToFeaturize() and
|
||||
(
|
||||
if strictcount(getTokenFeature(endpoint, featureName)) = 1
|
||||
then featureValue = getTokenFeature(endpoint, featureName)
|
||||
else (
|
||||
// Performance note: this is a Cartesian product between all endpoints and feature names.
|
||||
featureValue = "" and featureName = getASupportedFeatureName()
|
||||
)
|
||||
)
|
||||
featureValue = getTokenFeature(endpoint, featureName)
|
||||
}
|
||||
|
||||
@@ -87,23 +87,19 @@ module ModelScoring {
|
||||
class RelevantFeaturizationConfig extends EndpointFeatures::FeaturizationConfig {
|
||||
RelevantFeaturizationConfig() { this = "RelevantFeaturization" }
|
||||
|
||||
override DataFlow::Node getAnEndpointToFeaturize() {
|
||||
getCfg().isEffectiveSource(result) and any(DataFlow::Configuration cfg).hasFlow(result, _)
|
||||
override DataFlow::Node getAnEndpointToFeaturize() { getCfg().isEffectiveSource(result) and any(DataFlow::Configuration cfg).hasFlow(result, _)
|
||||
or
|
||||
getCfg().isEffectiveSink(result) and any(DataFlow::Configuration cfg).hasFlow(_, result)
|
||||
}
|
||||
getCfg().isEffectiveSink(result) and any(DataFlow::Configuration cfg).hasFlow(_, result) }
|
||||
}
|
||||
|
||||
DataFlow::Node getARequestedEndpoint() {
|
||||
result = any(EndpointFeatures::FeaturizationConfig cfg).getAnEndpointToFeaturize()
|
||||
}
|
||||
DataFlow::Node getARequestedEndpoint() { result = any(EndpointFeatures::FeaturizationConfig cfg).getAnEndpointToFeaturize() }
|
||||
|
||||
private int getARequestedEndpointType() { result = any(EndpointType type).getEncoding() }
|
||||
|
||||
predicate endpointScores(DataFlow::Node endpoint, int encodedEndpointType, float score) =
|
||||
scoreEndpoints(getARequestedEndpoint/0, getARequestedEndpointType/0,
|
||||
EndpointFeatures::tokenFeatures/3, getACompatibleModelChecksum/0)(endpoint,
|
||||
encodedEndpointType, score)
|
||||
scoreEndpoints(getARequestedEndpoint/0, EndpointFeatures::tokenFeatures/3,
|
||||
EndpointFeatures::getASupportedFeatureName/0, getARequestedEndpointType/0,
|
||||
getACompatibleModelChecksum/0)(endpoint, encodedEndpointType, score)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* value `nonzero`;
|
||||
*
|
||||
* - at other times, the analysis does not have enough information
|
||||
* to precisely model the behavior of certain program elements:
|
||||
* to precisely model the behaviour of certain program elements:
|
||||
* for example, the current flow analysis is intra-procedural,
|
||||
* so it does not model parameter passing or return values, and
|
||||
* hence has to make worst-case assumptions about the possible
|
||||
|
||||
@@ -1035,7 +1035,7 @@ module DataFlow {
|
||||
* Provides classes representing various kinds of calls.
|
||||
*
|
||||
* Subclass the classes in this module to introduce new kinds of calls. If you want to
|
||||
* refine the behavior of the analysis on existing kinds of calls, subclass `InvokeNode`
|
||||
* refine the behaviour of the analysis on existing kinds of calls, subclass `InvokeNode`
|
||||
* instead.
|
||||
*/
|
||||
module Impl {
|
||||
|
||||
@@ -551,11 +551,9 @@ module Templating {
|
||||
private class MustacheStyleSyntax extends TemplateSyntax {
|
||||
MustacheStyleSyntax() { this = "mustache" }
|
||||
|
||||
override string getRawInterpolationRegexp() {
|
||||
result = "(?s)\\{\\{\\{(.*?)\\}\\}\\}|\\{\\{&(.*?)\\}\\}"
|
||||
}
|
||||
override string getRawInterpolationRegexp() { result = "(?s)\\{\\{\\{(.*?)\\}\\}\\}" }
|
||||
|
||||
override string getEscapingInterpolationRegexp() { result = "(?s)\\{\\{[^{&](.*?)\\}\\}" }
|
||||
override string getEscapingInterpolationRegexp() { result = "(?s)\\{\\{[^{](.*?)\\}\\}" }
|
||||
|
||||
override string getAFileExtension() { result = ["hbs", "njk"] }
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import javascript
|
||||
/**
|
||||
* INTERNAL: Do not use in ordinary queries.
|
||||
*
|
||||
* Extraction metrics for profiling extraction behaviors.
|
||||
* Extraction metrics for profiling extraction behaviours.
|
||||
*/
|
||||
module ExtractionMetrics {
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @name Missing `MessageEvent.origin` verification in `postMessage` handlers
|
||||
* @description Missing the `MessageEvent.origin` verification in `postMessage` handlers, allows any windows to send arbitrary data to the `MessageEvent` listener.
|
||||
* This could lead to unexpected behavior, especially when `MessageEvent.data` is used in an unsafe way.
|
||||
* This could lead to unexpected behaviour, especially when `MessageEvent.data` is used in an unsafe way.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
|
||||
@@ -48,15 +48,15 @@ nodes
|
||||
| views/ejs_sinks.ejs:21:39:21:69 | <%= dataInEventHandlerString %> |
|
||||
| views/ejs_sinks.ejs:21:39:21:69 | <%= dataInEventHandlerString %> |
|
||||
| views/ejs_sinks.ejs:21:43:21:66 | dataInE ... rString |
|
||||
| views/hbs_sinks.hbs:25:39:25:63 | {{ dataInGeneratedCode }} |
|
||||
| views/hbs_sinks.hbs:25:39:25:63 | {{ dataInGeneratedCode }} |
|
||||
| views/hbs_sinks.hbs:25:42:25:60 | dataInGeneratedCode |
|
||||
| views/hbs_sinks.hbs:28:19:28:38 | {{ backslashSink1 }} |
|
||||
| views/hbs_sinks.hbs:28:19:28:38 | {{ backslashSink1 }} |
|
||||
| views/hbs_sinks.hbs:28:22:28:35 | backslashSink1 |
|
||||
| views/hbs_sinks.hbs:33:39:33:68 | {{ dataInEventHandlerString }} |
|
||||
| views/hbs_sinks.hbs:33:39:33:68 | {{ dataInEventHandlerString }} |
|
||||
| views/hbs_sinks.hbs:33:42:33:65 | dataInE ... rString |
|
||||
| views/hbs_sinks.hbs:13:39:13:63 | {{ dataInGeneratedCode }} |
|
||||
| views/hbs_sinks.hbs:13:39:13:63 | {{ dataInGeneratedCode }} |
|
||||
| views/hbs_sinks.hbs:13:42:13:60 | dataInGeneratedCode |
|
||||
| views/hbs_sinks.hbs:16:19:16:38 | {{ backslashSink1 }} |
|
||||
| views/hbs_sinks.hbs:16:19:16:38 | {{ backslashSink1 }} |
|
||||
| views/hbs_sinks.hbs:16:22:16:35 | backslashSink1 |
|
||||
| views/hbs_sinks.hbs:21:39:21:68 | {{ dataInEventHandlerString }} |
|
||||
| views/hbs_sinks.hbs:21:39:21:68 | {{ dataInEventHandlerString }} |
|
||||
| views/hbs_sinks.hbs:21:42:21:65 | dataInE ... rString |
|
||||
| views/njk_sinks.njk:13:39:13:63 | {{ dataInGeneratedCode }} |
|
||||
| views/njk_sinks.njk:13:39:13:63 | {{ dataInGeneratedCode }} |
|
||||
| views/njk_sinks.njk:13:42:13:60 | dataInGeneratedCode |
|
||||
@@ -86,12 +86,12 @@ edges
|
||||
| app.js:17:25:17:48 | req.que ... shSink1 | views/ejs_sinks.ejs:16:23:16:36 | backslashSink1 |
|
||||
| app.js:19:35:19:68 | req.que ... rString | views/ejs_sinks.ejs:21:43:21:66 | dataInE ... rString |
|
||||
| app.js:19:35:19:68 | req.que ... rString | views/ejs_sinks.ejs:21:43:21:66 | dataInE ... rString |
|
||||
| app.js:34:30:34:58 | req.que ... tedCode | views/hbs_sinks.hbs:25:42:25:60 | dataInGeneratedCode |
|
||||
| app.js:34:30:34:58 | req.que ... tedCode | views/hbs_sinks.hbs:25:42:25:60 | dataInGeneratedCode |
|
||||
| app.js:36:25:36:48 | req.que ... shSink1 | views/hbs_sinks.hbs:28:22:28:35 | backslashSink1 |
|
||||
| app.js:36:25:36:48 | req.que ... shSink1 | views/hbs_sinks.hbs:28:22:28:35 | backslashSink1 |
|
||||
| app.js:38:35:38:68 | req.que ... rString | views/hbs_sinks.hbs:33:42:33:65 | dataInE ... rString |
|
||||
| app.js:38:35:38:68 | req.que ... rString | views/hbs_sinks.hbs:33:42:33:65 | dataInE ... rString |
|
||||
| app.js:34:30:34:58 | req.que ... tedCode | views/hbs_sinks.hbs:13:42:13:60 | dataInGeneratedCode |
|
||||
| app.js:34:30:34:58 | req.que ... tedCode | views/hbs_sinks.hbs:13:42:13:60 | dataInGeneratedCode |
|
||||
| app.js:36:25:36:48 | req.que ... shSink1 | views/hbs_sinks.hbs:16:22:16:35 | backslashSink1 |
|
||||
| app.js:36:25:36:48 | req.que ... shSink1 | views/hbs_sinks.hbs:16:22:16:35 | backslashSink1 |
|
||||
| app.js:38:35:38:68 | req.que ... rString | views/hbs_sinks.hbs:21:42:21:65 | dataInE ... rString |
|
||||
| app.js:38:35:38:68 | req.que ... rString | views/hbs_sinks.hbs:21:42:21:65 | dataInE ... rString |
|
||||
| app.js:53:30:53:58 | req.que ... tedCode | views/njk_sinks.njk:13:42:13:60 | dataInGeneratedCode |
|
||||
| app.js:53:30:53:58 | req.que ... tedCode | views/njk_sinks.njk:13:42:13:60 | dataInGeneratedCode |
|
||||
| app.js:54:33:54:64 | req.que ... CodeRaw | views/njk_sinks.njk:14:45:14:66 | dataInG ... CodeRaw |
|
||||
@@ -126,12 +126,12 @@ edges
|
||||
| views/ejs_sinks.ejs:16:23:16:36 | backslashSink1 | views/ejs_sinks.ejs:16:19:16:39 | <%= backslashSink1 %> |
|
||||
| views/ejs_sinks.ejs:21:43:21:66 | dataInE ... rString | views/ejs_sinks.ejs:21:39:21:69 | <%= dataInEventHandlerString %> |
|
||||
| views/ejs_sinks.ejs:21:43:21:66 | dataInE ... rString | views/ejs_sinks.ejs:21:39:21:69 | <%= dataInEventHandlerString %> |
|
||||
| views/hbs_sinks.hbs:25:42:25:60 | dataInGeneratedCode | views/hbs_sinks.hbs:25:39:25:63 | {{ dataInGeneratedCode }} |
|
||||
| views/hbs_sinks.hbs:25:42:25:60 | dataInGeneratedCode | views/hbs_sinks.hbs:25:39:25:63 | {{ dataInGeneratedCode }} |
|
||||
| views/hbs_sinks.hbs:28:22:28:35 | backslashSink1 | views/hbs_sinks.hbs:28:19:28:38 | {{ backslashSink1 }} |
|
||||
| views/hbs_sinks.hbs:28:22:28:35 | backslashSink1 | views/hbs_sinks.hbs:28:19:28:38 | {{ backslashSink1 }} |
|
||||
| views/hbs_sinks.hbs:33:42:33:65 | dataInE ... rString | views/hbs_sinks.hbs:33:39:33:68 | {{ dataInEventHandlerString }} |
|
||||
| views/hbs_sinks.hbs:33:42:33:65 | dataInE ... rString | views/hbs_sinks.hbs:33:39:33:68 | {{ dataInEventHandlerString }} |
|
||||
| views/hbs_sinks.hbs:13:42:13:60 | dataInGeneratedCode | views/hbs_sinks.hbs:13:39:13:63 | {{ dataInGeneratedCode }} |
|
||||
| views/hbs_sinks.hbs:13:42:13:60 | dataInGeneratedCode | views/hbs_sinks.hbs:13:39:13:63 | {{ dataInGeneratedCode }} |
|
||||
| views/hbs_sinks.hbs:16:22:16:35 | backslashSink1 | views/hbs_sinks.hbs:16:19:16:38 | {{ backslashSink1 }} |
|
||||
| views/hbs_sinks.hbs:16:22:16:35 | backslashSink1 | views/hbs_sinks.hbs:16:19:16:38 | {{ backslashSink1 }} |
|
||||
| views/hbs_sinks.hbs:21:42:21:65 | dataInE ... rString | views/hbs_sinks.hbs:21:39:21:68 | {{ dataInEventHandlerString }} |
|
||||
| views/hbs_sinks.hbs:21:42:21:65 | dataInE ... rString | views/hbs_sinks.hbs:21:39:21:68 | {{ dataInEventHandlerString }} |
|
||||
| views/njk_sinks.njk:13:42:13:60 | dataInGeneratedCode | views/njk_sinks.njk:13:39:13:63 | {{ dataInGeneratedCode }} |
|
||||
| views/njk_sinks.njk:13:42:13:60 | dataInGeneratedCode | views/njk_sinks.njk:13:39:13:63 | {{ dataInGeneratedCode }} |
|
||||
| views/njk_sinks.njk:14:45:14:66 | dataInG ... CodeRaw | views/njk_sinks.njk:14:45:14:73 | dataInG ... \| safe |
|
||||
@@ -156,9 +156,9 @@ edges
|
||||
| views/ejs_sinks.ejs:13:39:13:64 | <%= dataInGeneratedCode %> | app.js:15:30:15:58 | req.que ... tedCode | views/ejs_sinks.ejs:13:39:13:64 | <%= dataInGeneratedCode %> | $@ flows to here and is interpreted as code. | app.js:15:30:15:58 | req.que ... tedCode | User-provided value |
|
||||
| views/ejs_sinks.ejs:16:19:16:39 | <%= backslashSink1 %> | app.js:17:25:17:48 | req.que ... shSink1 | views/ejs_sinks.ejs:16:19:16:39 | <%= backslashSink1 %> | $@ flows to here and is interpreted as code. | app.js:17:25:17:48 | req.que ... shSink1 | User-provided value |
|
||||
| views/ejs_sinks.ejs:21:39:21:69 | <%= dataInEventHandlerString %> | app.js:19:35:19:68 | req.que ... rString | views/ejs_sinks.ejs:21:39:21:69 | <%= dataInEventHandlerString %> | $@ flows to here and is interpreted as code. | app.js:19:35:19:68 | req.que ... rString | User-provided value |
|
||||
| views/hbs_sinks.hbs:25:39:25:63 | {{ dataInGeneratedCode }} | app.js:34:30:34:58 | req.que ... tedCode | views/hbs_sinks.hbs:25:39:25:63 | {{ dataInGeneratedCode }} | $@ flows to here and is interpreted as code. | app.js:34:30:34:58 | req.que ... tedCode | User-provided value |
|
||||
| views/hbs_sinks.hbs:28:19:28:38 | {{ backslashSink1 }} | app.js:36:25:36:48 | req.que ... shSink1 | views/hbs_sinks.hbs:28:19:28:38 | {{ backslashSink1 }} | $@ flows to here and is interpreted as code. | app.js:36:25:36:48 | req.que ... shSink1 | User-provided value |
|
||||
| views/hbs_sinks.hbs:33:39:33:68 | {{ dataInEventHandlerString }} | app.js:38:35:38:68 | req.que ... rString | views/hbs_sinks.hbs:33:39:33:68 | {{ dataInEventHandlerString }} | $@ flows to here and is interpreted as code. | app.js:38:35:38:68 | req.que ... rString | User-provided value |
|
||||
| views/hbs_sinks.hbs:13:39:13:63 | {{ dataInGeneratedCode }} | app.js:34:30:34:58 | req.que ... tedCode | views/hbs_sinks.hbs:13:39:13:63 | {{ dataInGeneratedCode }} | $@ flows to here and is interpreted as code. | app.js:34:30:34:58 | req.que ... tedCode | User-provided value |
|
||||
| views/hbs_sinks.hbs:16:19:16:38 | {{ backslashSink1 }} | app.js:36:25:36:48 | req.que ... shSink1 | views/hbs_sinks.hbs:16:19:16:38 | {{ backslashSink1 }} | $@ flows to here and is interpreted as code. | app.js:36:25:36:48 | req.que ... shSink1 | User-provided value |
|
||||
| views/hbs_sinks.hbs:21:39:21:68 | {{ dataInEventHandlerString }} | app.js:38:35:38:68 | req.que ... rString | views/hbs_sinks.hbs:21:39:21:68 | {{ dataInEventHandlerString }} | $@ flows to here and is interpreted as code. | app.js:38:35:38:68 | req.que ... rString | User-provided value |
|
||||
| views/njk_sinks.njk:13:39:13:63 | {{ dataInGeneratedCode }} | app.js:53:30:53:58 | req.que ... tedCode | views/njk_sinks.njk:13:39:13:63 | {{ dataInGeneratedCode }} | $@ flows to here and is interpreted as code. | app.js:53:30:53:58 | req.que ... tedCode | User-provided value |
|
||||
| views/njk_sinks.njk:14:42:14:76 | {{ dataInGeneratedCodeRaw \| safe }} | app.js:54:33:54:64 | req.que ... CodeRaw | views/njk_sinks.njk:14:42:14:76 | {{ dataInGeneratedCodeRaw \| safe }} | $@ flows to here and is interpreted as code. | app.js:54:33:54:64 | req.que ... CodeRaw | User-provided value |
|
||||
| views/njk_sinks.njk:15:46:15:91 | {{ dataInGeneratedCodeJsonRaw \| json \| safe }} | app.js:55:37:55:72 | req.que ... JsonRaw | views/njk_sinks.njk:15:46:15:91 | {{ dataInGeneratedCodeJsonRaw \| json \| safe }} | $@ flows to here and is interpreted as code. | app.js:55:37:55:72 | req.que ... JsonRaw | User-provided value |
|
||||
|
||||
@@ -114,36 +114,21 @@ nodes
|
||||
| views/ejs_sinks.ejs:22:39:22:72 | <%- dataInEventHandlerStringRaw %> |
|
||||
| views/ejs_sinks.ejs:22:43:22:69 | dataInE ... ringRaw |
|
||||
| views/ejs_sinks.ejs:24:44:24:50 | rawHtml |
|
||||
| views/hbs_sinks.hbs:9:9:9:23 | {{{ rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:9:9:9:23 | {{{ rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:9:13:9:19 | rawHtml |
|
||||
| views/hbs_sinks.hbs:10:9:10:23 | {{{~rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:10:9:10:23 | {{{~rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:10:13:10:19 | rawHtml |
|
||||
| views/hbs_sinks.hbs:11:9:11:23 | {{{ rawHtml~}}} |
|
||||
| views/hbs_sinks.hbs:11:9:11:23 | {{{ rawHtml~}}} |
|
||||
| views/hbs_sinks.hbs:11:13:11:19 | rawHtml |
|
||||
| views/hbs_sinks.hbs:12:9:12:23 | {{{~rawHtml~}}} |
|
||||
| views/hbs_sinks.hbs:12:9:12:23 | {{{~rawHtml~}}} |
|
||||
| views/hbs_sinks.hbs:12:13:12:19 | rawHtml |
|
||||
| views/hbs_sinks.hbs:13:9:13:25 | {{{~ rawHtml ~}}} |
|
||||
| views/hbs_sinks.hbs:13:9:13:25 | {{{~ rawHtml ~}}} |
|
||||
| views/hbs_sinks.hbs:13:14:13:20 | rawHtml |
|
||||
| views/hbs_sinks.hbs:15:9:15:22 | {{& rawHtml }} |
|
||||
| views/hbs_sinks.hbs:15:9:15:22 | {{& rawHtml }} |
|
||||
| views/hbs_sinks.hbs:15:13:15:19 | rawHtml |
|
||||
| views/hbs_sinks.hbs:19:9:19:34 | {{{ object.rawHtmlProp }}} |
|
||||
| views/hbs_sinks.hbs:19:9:19:34 | {{{ object.rawHtmlProp }}} |
|
||||
| views/hbs_sinks.hbs:19:13:19:30 | object.rawHtmlProp |
|
||||
| views/hbs_sinks.hbs:23:43:23:72 | {{{ dataInStringLiteralRaw }}} |
|
||||
| views/hbs_sinks.hbs:23:43:23:72 | {{{ dataInStringLiteralRaw }}} |
|
||||
| views/hbs_sinks.hbs:23:47:23:68 | dataInS ... eralRaw |
|
||||
| views/hbs_sinks.hbs:26:42:26:71 | {{{ dataInGeneratedCodeRaw }}} |
|
||||
| views/hbs_sinks.hbs:26:42:26:71 | {{{ dataInGeneratedCodeRaw }}} |
|
||||
| views/hbs_sinks.hbs:26:46:26:67 | dataInG ... CodeRaw |
|
||||
| views/hbs_sinks.hbs:34:39:34:73 | {{{ dataInEventHandlerStringRaw }}} |
|
||||
| views/hbs_sinks.hbs:34:39:34:73 | {{{ dataInEventHandlerStringRaw }}} |
|
||||
| views/hbs_sinks.hbs:34:43:34:69 | dataInE ... ringRaw |
|
||||
| views/hbs_sinks.hbs:4:9:4:23 | {{{ rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:4:9:4:23 | {{{ rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:4:13:4:19 | rawHtml |
|
||||
| views/hbs_sinks.hbs:7:9:7:34 | {{{ object.rawHtmlProp }}} |
|
||||
| views/hbs_sinks.hbs:7:9:7:34 | {{{ object.rawHtmlProp }}} |
|
||||
| views/hbs_sinks.hbs:7:13:7:30 | object.rawHtmlProp |
|
||||
| views/hbs_sinks.hbs:11:43:11:72 | {{{ dataInStringLiteralRaw }}} |
|
||||
| views/hbs_sinks.hbs:11:43:11:72 | {{{ dataInStringLiteralRaw }}} |
|
||||
| views/hbs_sinks.hbs:11:47:11:68 | dataInS ... eralRaw |
|
||||
| views/hbs_sinks.hbs:14:42:14:71 | {{{ dataInGeneratedCodeRaw }}} |
|
||||
| views/hbs_sinks.hbs:14:42:14:71 | {{{ dataInGeneratedCodeRaw }}} |
|
||||
| views/hbs_sinks.hbs:14:46:14:67 | dataInG ... CodeRaw |
|
||||
| views/hbs_sinks.hbs:22:39:22:73 | {{{ dataInEventHandlerStringRaw }}} |
|
||||
| views/hbs_sinks.hbs:22:39:22:73 | {{{ dataInEventHandlerStringRaw }}} |
|
||||
| views/hbs_sinks.hbs:22:43:22:69 | dataInE ... ringRaw |
|
||||
| views/njk_sinks.njk:4:12:4:18 | rawHtml |
|
||||
| views/njk_sinks.njk:4:12:4:18 | rawHtml |
|
||||
| views/njk_sinks.njk:7:12:7:29 | object.rawHtmlProp |
|
||||
@@ -172,26 +157,16 @@ edges
|
||||
| app.js:16:33:16:64 | req.que ... CodeRaw | views/ejs_sinks.ejs:14:46:14:67 | dataInG ... CodeRaw |
|
||||
| app.js:20:38:20:74 | req.que ... ringRaw | views/ejs_sinks.ejs:22:43:22:69 | dataInE ... ringRaw |
|
||||
| app.js:20:38:20:74 | req.que ... ringRaw | views/ejs_sinks.ejs:22:43:22:69 | dataInE ... ringRaw |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:9:13:9:19 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:9:13:9:19 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:10:13:10:19 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:10:13:10:19 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:11:13:11:19 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:11:13:11:19 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:12:13:12:19 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:12:13:12:19 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:13:14:13:20 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:13:14:13:20 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:15:13:15:19 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:15:13:15:19 | rawHtml |
|
||||
| app.js:30:26:30:46 | req.que ... tmlProp | views/hbs_sinks.hbs:19:13:19:30 | object.rawHtmlProp |
|
||||
| app.js:30:26:30:46 | req.que ... tmlProp | views/hbs_sinks.hbs:19:13:19:30 | object.rawHtmlProp |
|
||||
| app.js:33:33:33:64 | req.que ... eralRaw | views/hbs_sinks.hbs:23:47:23:68 | dataInS ... eralRaw |
|
||||
| app.js:33:33:33:64 | req.que ... eralRaw | views/hbs_sinks.hbs:23:47:23:68 | dataInS ... eralRaw |
|
||||
| app.js:35:33:35:64 | req.que ... CodeRaw | views/hbs_sinks.hbs:26:46:26:67 | dataInG ... CodeRaw |
|
||||
| app.js:35:33:35:64 | req.que ... CodeRaw | views/hbs_sinks.hbs:26:46:26:67 | dataInG ... CodeRaw |
|
||||
| app.js:39:38:39:74 | req.que ... ringRaw | views/hbs_sinks.hbs:34:43:34:69 | dataInE ... ringRaw |
|
||||
| app.js:39:38:39:74 | req.que ... ringRaw | views/hbs_sinks.hbs:34:43:34:69 | dataInE ... ringRaw |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:4:13:4:19 | rawHtml |
|
||||
| app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:4:13:4:19 | rawHtml |
|
||||
| app.js:30:26:30:46 | req.que ... tmlProp | views/hbs_sinks.hbs:7:13:7:30 | object.rawHtmlProp |
|
||||
| app.js:30:26:30:46 | req.que ... tmlProp | views/hbs_sinks.hbs:7:13:7:30 | object.rawHtmlProp |
|
||||
| app.js:33:33:33:64 | req.que ... eralRaw | views/hbs_sinks.hbs:11:47:11:68 | dataInS ... eralRaw |
|
||||
| app.js:33:33:33:64 | req.que ... eralRaw | views/hbs_sinks.hbs:11:47:11:68 | dataInS ... eralRaw |
|
||||
| app.js:35:33:35:64 | req.que ... CodeRaw | views/hbs_sinks.hbs:14:46:14:67 | dataInG ... CodeRaw |
|
||||
| app.js:35:33:35:64 | req.que ... CodeRaw | views/hbs_sinks.hbs:14:46:14:67 | dataInG ... CodeRaw |
|
||||
| app.js:39:38:39:74 | req.que ... ringRaw | views/hbs_sinks.hbs:22:43:22:69 | dataInE ... ringRaw |
|
||||
| app.js:39:38:39:74 | req.que ... ringRaw | views/hbs_sinks.hbs:22:43:22:69 | dataInE ... ringRaw |
|
||||
| app.js:46:18:46:34 | req.query.rawHtml | views/njk_sinks.njk:4:12:4:18 | rawHtml |
|
||||
| app.js:46:18:46:34 | req.query.rawHtml | views/njk_sinks.njk:4:12:4:18 | rawHtml |
|
||||
| app.js:46:18:46:34 | req.query.rawHtml | views/njk_sinks.njk:4:12:4:18 | rawHtml |
|
||||
@@ -281,26 +256,16 @@ edges
|
||||
| views/ejs_sinks.ejs:22:43:22:69 | dataInE ... ringRaw | views/ejs_sinks.ejs:22:39:22:72 | <%- dataInEventHandlerStringRaw %> |
|
||||
| views/ejs_sinks.ejs:22:43:22:69 | dataInE ... ringRaw | views/ejs_sinks.ejs:22:39:22:72 | <%- dataInEventHandlerStringRaw %> |
|
||||
| views/ejs_sinks.ejs:24:44:24:50 | rawHtml | views/ejs_include1.ejs:1:5:1:7 | foo |
|
||||
| views/hbs_sinks.hbs:9:13:9:19 | rawHtml | views/hbs_sinks.hbs:9:9:9:23 | {{{ rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:9:13:9:19 | rawHtml | views/hbs_sinks.hbs:9:9:9:23 | {{{ rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:10:13:10:19 | rawHtml | views/hbs_sinks.hbs:10:9:10:23 | {{{~rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:10:13:10:19 | rawHtml | views/hbs_sinks.hbs:10:9:10:23 | {{{~rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:11:13:11:19 | rawHtml | views/hbs_sinks.hbs:11:9:11:23 | {{{ rawHtml~}}} |
|
||||
| views/hbs_sinks.hbs:11:13:11:19 | rawHtml | views/hbs_sinks.hbs:11:9:11:23 | {{{ rawHtml~}}} |
|
||||
| views/hbs_sinks.hbs:12:13:12:19 | rawHtml | views/hbs_sinks.hbs:12:9:12:23 | {{{~rawHtml~}}} |
|
||||
| views/hbs_sinks.hbs:12:13:12:19 | rawHtml | views/hbs_sinks.hbs:12:9:12:23 | {{{~rawHtml~}}} |
|
||||
| views/hbs_sinks.hbs:13:14:13:20 | rawHtml | views/hbs_sinks.hbs:13:9:13:25 | {{{~ rawHtml ~}}} |
|
||||
| views/hbs_sinks.hbs:13:14:13:20 | rawHtml | views/hbs_sinks.hbs:13:9:13:25 | {{{~ rawHtml ~}}} |
|
||||
| views/hbs_sinks.hbs:15:13:15:19 | rawHtml | views/hbs_sinks.hbs:15:9:15:22 | {{& rawHtml }} |
|
||||
| views/hbs_sinks.hbs:15:13:15:19 | rawHtml | views/hbs_sinks.hbs:15:9:15:22 | {{& rawHtml }} |
|
||||
| views/hbs_sinks.hbs:19:13:19:30 | object.rawHtmlProp | views/hbs_sinks.hbs:19:9:19:34 | {{{ object.rawHtmlProp }}} |
|
||||
| views/hbs_sinks.hbs:19:13:19:30 | object.rawHtmlProp | views/hbs_sinks.hbs:19:9:19:34 | {{{ object.rawHtmlProp }}} |
|
||||
| views/hbs_sinks.hbs:23:47:23:68 | dataInS ... eralRaw | views/hbs_sinks.hbs:23:43:23:72 | {{{ dataInStringLiteralRaw }}} |
|
||||
| views/hbs_sinks.hbs:23:47:23:68 | dataInS ... eralRaw | views/hbs_sinks.hbs:23:43:23:72 | {{{ dataInStringLiteralRaw }}} |
|
||||
| views/hbs_sinks.hbs:26:46:26:67 | dataInG ... CodeRaw | views/hbs_sinks.hbs:26:42:26:71 | {{{ dataInGeneratedCodeRaw }}} |
|
||||
| views/hbs_sinks.hbs:26:46:26:67 | dataInG ... CodeRaw | views/hbs_sinks.hbs:26:42:26:71 | {{{ dataInGeneratedCodeRaw }}} |
|
||||
| views/hbs_sinks.hbs:34:43:34:69 | dataInE ... ringRaw | views/hbs_sinks.hbs:34:39:34:73 | {{{ dataInEventHandlerStringRaw }}} |
|
||||
| views/hbs_sinks.hbs:34:43:34:69 | dataInE ... ringRaw | views/hbs_sinks.hbs:34:39:34:73 | {{{ dataInEventHandlerStringRaw }}} |
|
||||
| views/hbs_sinks.hbs:4:13:4:19 | rawHtml | views/hbs_sinks.hbs:4:9:4:23 | {{{ rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:4:13:4:19 | rawHtml | views/hbs_sinks.hbs:4:9:4:23 | {{{ rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:7:13:7:30 | object.rawHtmlProp | views/hbs_sinks.hbs:7:9:7:34 | {{{ object.rawHtmlProp }}} |
|
||||
| views/hbs_sinks.hbs:7:13:7:30 | object.rawHtmlProp | views/hbs_sinks.hbs:7:9:7:34 | {{{ object.rawHtmlProp }}} |
|
||||
| views/hbs_sinks.hbs:11:47:11:68 | dataInS ... eralRaw | views/hbs_sinks.hbs:11:43:11:72 | {{{ dataInStringLiteralRaw }}} |
|
||||
| views/hbs_sinks.hbs:11:47:11:68 | dataInS ... eralRaw | views/hbs_sinks.hbs:11:43:11:72 | {{{ dataInStringLiteralRaw }}} |
|
||||
| views/hbs_sinks.hbs:14:46:14:67 | dataInG ... CodeRaw | views/hbs_sinks.hbs:14:42:14:71 | {{{ dataInGeneratedCodeRaw }}} |
|
||||
| views/hbs_sinks.hbs:14:46:14:67 | dataInG ... CodeRaw | views/hbs_sinks.hbs:14:42:14:71 | {{{ dataInGeneratedCodeRaw }}} |
|
||||
| views/hbs_sinks.hbs:22:43:22:69 | dataInE ... ringRaw | views/hbs_sinks.hbs:22:39:22:73 | {{{ dataInEventHandlerStringRaw }}} |
|
||||
| views/hbs_sinks.hbs:22:43:22:69 | dataInE ... ringRaw | views/hbs_sinks.hbs:22:39:22:73 | {{{ dataInEventHandlerStringRaw }}} |
|
||||
| views/njk_sinks.njk:15:49:15:74 | dataInG ... JsonRaw | views/njk_sinks.njk:15:49:15:81 | dataInG ... \| json |
|
||||
| views/njk_sinks.njk:15:49:15:74 | dataInG ... JsonRaw | views/njk_sinks.njk:15:49:15:81 | dataInG ... \| json |
|
||||
#select
|
||||
@@ -326,16 +291,11 @@ edges
|
||||
| views/ejs_sinks.ejs:11:43:11:71 | <%- dataInStringLiteralRaw %> | app.js:14:33:14:64 | req.que ... eralRaw | views/ejs_sinks.ejs:11:43:11:71 | <%- dataInStringLiteralRaw %> | Cross-site scripting vulnerability due to $@. | app.js:14:33:14:64 | req.que ... eralRaw | user-provided value |
|
||||
| views/ejs_sinks.ejs:14:42:14:70 | <%- dataInGeneratedCodeRaw %> | app.js:16:33:16:64 | req.que ... CodeRaw | views/ejs_sinks.ejs:14:42:14:70 | <%- dataInGeneratedCodeRaw %> | Cross-site scripting vulnerability due to $@. | app.js:16:33:16:64 | req.que ... CodeRaw | user-provided value |
|
||||
| views/ejs_sinks.ejs:22:39:22:72 | <%- dataInEventHandlerStringRaw %> | app.js:20:38:20:74 | req.que ... ringRaw | views/ejs_sinks.ejs:22:39:22:72 | <%- dataInEventHandlerStringRaw %> | Cross-site scripting vulnerability due to $@. | app.js:20:38:20:74 | req.que ... ringRaw | user-provided value |
|
||||
| views/hbs_sinks.hbs:9:9:9:23 | {{{ rawHtml }}} | app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:9:9:9:23 | {{{ rawHtml }}} | Cross-site scripting vulnerability due to $@. | app.js:27:18:27:34 | req.query.rawHtml | user-provided value |
|
||||
| views/hbs_sinks.hbs:10:9:10:23 | {{{~rawHtml }}} | app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:10:9:10:23 | {{{~rawHtml }}} | Cross-site scripting vulnerability due to $@. | app.js:27:18:27:34 | req.query.rawHtml | user-provided value |
|
||||
| views/hbs_sinks.hbs:11:9:11:23 | {{{ rawHtml~}}} | app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:11:9:11:23 | {{{ rawHtml~}}} | Cross-site scripting vulnerability due to $@. | app.js:27:18:27:34 | req.query.rawHtml | user-provided value |
|
||||
| views/hbs_sinks.hbs:12:9:12:23 | {{{~rawHtml~}}} | app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:12:9:12:23 | {{{~rawHtml~}}} | Cross-site scripting vulnerability due to $@. | app.js:27:18:27:34 | req.query.rawHtml | user-provided value |
|
||||
| views/hbs_sinks.hbs:13:9:13:25 | {{{~ rawHtml ~}}} | app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:13:9:13:25 | {{{~ rawHtml ~}}} | Cross-site scripting vulnerability due to $@. | app.js:27:18:27:34 | req.query.rawHtml | user-provided value |
|
||||
| views/hbs_sinks.hbs:15:9:15:22 | {{& rawHtml }} | app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:15:9:15:22 | {{& rawHtml }} | Cross-site scripting vulnerability due to $@. | app.js:27:18:27:34 | req.query.rawHtml | user-provided value |
|
||||
| views/hbs_sinks.hbs:19:9:19:34 | {{{ object.rawHtmlProp }}} | app.js:30:26:30:46 | req.que ... tmlProp | views/hbs_sinks.hbs:19:9:19:34 | {{{ object.rawHtmlProp }}} | Cross-site scripting vulnerability due to $@. | app.js:30:26:30:46 | req.que ... tmlProp | user-provided value |
|
||||
| views/hbs_sinks.hbs:23:43:23:72 | {{{ dataInStringLiteralRaw }}} | app.js:33:33:33:64 | req.que ... eralRaw | views/hbs_sinks.hbs:23:43:23:72 | {{{ dataInStringLiteralRaw }}} | Cross-site scripting vulnerability due to $@. | app.js:33:33:33:64 | req.que ... eralRaw | user-provided value |
|
||||
| views/hbs_sinks.hbs:26:42:26:71 | {{{ dataInGeneratedCodeRaw }}} | app.js:35:33:35:64 | req.que ... CodeRaw | views/hbs_sinks.hbs:26:42:26:71 | {{{ dataInGeneratedCodeRaw }}} | Cross-site scripting vulnerability due to $@. | app.js:35:33:35:64 | req.que ... CodeRaw | user-provided value |
|
||||
| views/hbs_sinks.hbs:34:39:34:73 | {{{ dataInEventHandlerStringRaw }}} | app.js:39:38:39:74 | req.que ... ringRaw | views/hbs_sinks.hbs:34:39:34:73 | {{{ dataInEventHandlerStringRaw }}} | Cross-site scripting vulnerability due to $@. | app.js:39:38:39:74 | req.que ... ringRaw | user-provided value |
|
||||
| views/hbs_sinks.hbs:4:9:4:23 | {{{ rawHtml }}} | app.js:27:18:27:34 | req.query.rawHtml | views/hbs_sinks.hbs:4:9:4:23 | {{{ rawHtml }}} | Cross-site scripting vulnerability due to $@. | app.js:27:18:27:34 | req.query.rawHtml | user-provided value |
|
||||
| views/hbs_sinks.hbs:7:9:7:34 | {{{ object.rawHtmlProp }}} | app.js:30:26:30:46 | req.que ... tmlProp | views/hbs_sinks.hbs:7:9:7:34 | {{{ object.rawHtmlProp }}} | Cross-site scripting vulnerability due to $@. | app.js:30:26:30:46 | req.que ... tmlProp | user-provided value |
|
||||
| views/hbs_sinks.hbs:11:43:11:72 | {{{ dataInStringLiteralRaw }}} | app.js:33:33:33:64 | req.que ... eralRaw | views/hbs_sinks.hbs:11:43:11:72 | {{{ dataInStringLiteralRaw }}} | Cross-site scripting vulnerability due to $@. | app.js:33:33:33:64 | req.que ... eralRaw | user-provided value |
|
||||
| views/hbs_sinks.hbs:14:42:14:71 | {{{ dataInGeneratedCodeRaw }}} | app.js:35:33:35:64 | req.que ... CodeRaw | views/hbs_sinks.hbs:14:42:14:71 | {{{ dataInGeneratedCodeRaw }}} | Cross-site scripting vulnerability due to $@. | app.js:35:33:35:64 | req.que ... CodeRaw | user-provided value |
|
||||
| views/hbs_sinks.hbs:22:39:22:73 | {{{ dataInEventHandlerStringRaw }}} | app.js:39:38:39:74 | req.que ... ringRaw | views/hbs_sinks.hbs:22:39:22:73 | {{{ dataInEventHandlerStringRaw }}} | Cross-site scripting vulnerability due to $@. | app.js:39:38:39:74 | req.que ... ringRaw | user-provided value |
|
||||
| views/njk_sinks.njk:4:12:4:18 | rawHtml | app.js:46:18:46:34 | req.query.rawHtml | views/njk_sinks.njk:4:12:4:18 | rawHtml | Cross-site scripting vulnerability due to $@. | app.js:46:18:46:34 | req.query.rawHtml | user-provided value |
|
||||
| views/njk_sinks.njk:7:12:7:29 | object.rawHtmlProp | app.js:49:26:49:46 | req.que ... tmlProp | views/njk_sinks.njk:7:12:7:29 | object.rawHtmlProp | Cross-site scripting vulnerability due to $@. | app.js:49:26:49:46 | req.que ... tmlProp | user-provided value |
|
||||
| views/njk_sinks.njk:11:46:11:67 | dataInS ... eralRaw | app.js:52:33:52:64 | req.que ... eralRaw | views/njk_sinks.njk:11:46:11:67 | dataInS ... eralRaw | Cross-site scripting vulnerability due to $@. | app.js:52:33:52:64 | req.que ... eralRaw | user-provided value |
|
||||
|
||||
@@ -59,17 +59,12 @@ xssSink
|
||||
| views/ejs_sinks.ejs:14:42:14:70 | <%- dataInGeneratedCodeRaw %> |
|
||||
| views/ejs_sinks.ejs:22:39:22:72 | <%- dataInEventHandlerStringRaw %> |
|
||||
| views/ejs_sinks.ejs:24:9:24:57 | <%- include('ejs_include1', { foo: rawHtml }) _%> |
|
||||
| views/hbs_sinks.hbs:9:9:9:23 | {{{ rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:10:9:10:23 | {{{~rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:11:9:11:23 | {{{ rawHtml~}}} |
|
||||
| views/hbs_sinks.hbs:12:9:12:23 | {{{~rawHtml~}}} |
|
||||
| views/hbs_sinks.hbs:13:9:13:25 | {{{~ rawHtml ~}}} |
|
||||
| views/hbs_sinks.hbs:15:9:15:22 | {{& rawHtml }} |
|
||||
| views/hbs_sinks.hbs:17:9:17:32 | {{{ rawHtmlSafeValue }}} |
|
||||
| views/hbs_sinks.hbs:19:9:19:34 | {{{ object.rawHtmlProp }}} |
|
||||
| views/hbs_sinks.hbs:23:43:23:72 | {{{ dataInStringLiteralRaw }}} |
|
||||
| views/hbs_sinks.hbs:26:42:26:71 | {{{ dataInGeneratedCodeRaw }}} |
|
||||
| views/hbs_sinks.hbs:34:39:34:73 | {{{ dataInEventHandlerStringRaw }}} |
|
||||
| views/hbs_sinks.hbs:4:9:4:23 | {{{ rawHtml }}} |
|
||||
| views/hbs_sinks.hbs:5:9:5:32 | {{{ rawHtmlSafeValue }}} |
|
||||
| views/hbs_sinks.hbs:7:9:7:34 | {{{ object.rawHtmlProp }}} |
|
||||
| views/hbs_sinks.hbs:11:43:11:72 | {{{ dataInStringLiteralRaw }}} |
|
||||
| views/hbs_sinks.hbs:14:42:14:71 | {{{ dataInGeneratedCodeRaw }}} |
|
||||
| views/hbs_sinks.hbs:22:39:22:73 | {{{ dataInEventHandlerStringRaw }}} |
|
||||
| views/instantiated_as_ejs.html:4:9:4:23 | <%- xss_sink %> |
|
||||
| views/instantiated_as_hbs.html:7:9:7:24 | {{{ xss_sink }}} |
|
||||
| views/njk_sinks.njk:4:12:4:18 | rawHtml |
|
||||
@@ -88,9 +83,9 @@ codeInjectionSink
|
||||
| views/ejs_sinks.ejs:13:39:13:64 | <%= dataInGeneratedCode %> |
|
||||
| views/ejs_sinks.ejs:16:19:16:39 | <%= backslashSink1 %> |
|
||||
| views/ejs_sinks.ejs:21:39:21:69 | <%= dataInEventHandlerString %> |
|
||||
| views/hbs_sinks.hbs:25:39:25:63 | {{ dataInGeneratedCode }} |
|
||||
| views/hbs_sinks.hbs:28:19:28:38 | {{ backslashSink1 }} |
|
||||
| views/hbs_sinks.hbs:33:39:33:68 | {{ dataInEventHandlerString }} |
|
||||
| views/hbs_sinks.hbs:13:39:13:63 | {{ dataInGeneratedCode }} |
|
||||
| views/hbs_sinks.hbs:16:19:16:38 | {{ backslashSink1 }} |
|
||||
| views/hbs_sinks.hbs:21:39:21:68 | {{ dataInEventHandlerString }} |
|
||||
| views/njk_sinks.njk:13:39:13:63 | {{ dataInGeneratedCode }} |
|
||||
| views/njk_sinks.njk:14:42:14:76 | {{ dataInGeneratedCodeRaw \| safe }} |
|
||||
| views/njk_sinks.njk:15:46:15:91 | {{ dataInGeneratedCodeJsonRaw \| json \| safe }} |
|
||||
|
||||
@@ -1,19 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
{{ escapedHtml }}
|
||||
{{~ escapedHtml }}
|
||||
{{ escapedHtml ~}}
|
||||
{{~ escapedHtml ~}}
|
||||
{{~escapedHtml~}}
|
||||
|
||||
{{{ rawHtml }}}
|
||||
{{{~rawHtml }}}
|
||||
{{{ rawHtml~}}}
|
||||
{{{~rawHtml~}}}
|
||||
{{{~ rawHtml ~}}}
|
||||
|
||||
{{& rawHtml }}
|
||||
|
||||
{{{ rawHtmlSafeValue }}}
|
||||
|
||||
{{{ object.rawHtmlProp }}}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
lgtm,codescanning
|
||||
* Two new queries have been added for detecting Server-side request forgery (SSRF). _Full server-side request forgery_ (`py/full-ssrf`) will only alert when the URL is fully user-controlled, and _Partial server-side request forgery_ (`py/partial-ssrf`) will alert when any part of the URL is user-controlled. Only `py/full-ssrf` will be run by default.
|
||||
* To support the new SSRF queries, the PyPI package `requests` have been modeled, along with `http.client.HTTP[S]Connection` from the standard library.
|
||||
@@ -812,72 +812,6 @@ module HTTP {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides classes for modeling HTTP clients. */
|
||||
module Client {
|
||||
/**
|
||||
* A data-flow node that makes an outgoing HTTP request.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `HTTP::Client::Request::Range` instead.
|
||||
*/
|
||||
class Request extends DataFlow::Node instanceof Request::Range {
|
||||
/**
|
||||
* Gets a data-flow node that contributes to the URL of the request.
|
||||
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
|
||||
*/
|
||||
DataFlow::Node getAUrlPart() { result = super.getAUrlPart() }
|
||||
|
||||
/** Gets a string that identifies the framework used for this request. */
|
||||
string getFramework() { result = super.getFramework() }
|
||||
|
||||
/**
|
||||
* Holds if this request is made using a mode that disables SSL/TLS
|
||||
* certificate validation, where `disablingNode` represents the point at
|
||||
* which the validation was disabled, and `argumentOrigin` represents the origin
|
||||
* of the argument that disabled the validation (which could be the same node as
|
||||
* `disablingNode`).
|
||||
*/
|
||||
predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
super.disablesCertificateValidation(disablingNode, argumentOrigin)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP requests. */
|
||||
module Request {
|
||||
/**
|
||||
* A data-flow node that makes an outgoing HTTP request.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `HTTP::Client::Request` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets a data-flow node that contributes to the URL of the request.
|
||||
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
|
||||
*/
|
||||
abstract DataFlow::Node getAUrlPart();
|
||||
|
||||
/** Gets a string that identifies the framework used for this request. */
|
||||
abstract string getFramework();
|
||||
|
||||
/**
|
||||
* Holds if this request is made using a mode that disables SSL/TLS
|
||||
* certificate validation, where `disablingNode` represents the point at
|
||||
* which the validation was disabled, and `argumentOrigin` represents the origin
|
||||
* of the argument that disabled the validation (which could be the same node as
|
||||
* `disablingNode`).
|
||||
*/
|
||||
abstract predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
);
|
||||
}
|
||||
}
|
||||
// TODO: investigate whether we should treat responses to client requests as
|
||||
// remote-flow-sources in general.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,6 @@ private import semmle.python.frameworks.Peewee
|
||||
private import semmle.python.frameworks.Psycopg2
|
||||
private import semmle.python.frameworks.Pydantic
|
||||
private import semmle.python.frameworks.PyMySQL
|
||||
private import semmle.python.frameworks.Requests
|
||||
private import semmle.python.frameworks.RestFramework
|
||||
private import semmle.python.frameworks.Rsa
|
||||
private import semmle.python.frameworks.RuamelYaml
|
||||
|
||||
@@ -15,23 +15,11 @@ module Consistency {
|
||||
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||
string toString() { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
|
||||
predicate uniqueEnclosingCallableExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
|
||||
predicate uniqueNodeLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
|
||||
predicate missingLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||
predicate postWithInFlowExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
|
||||
predicate reverseReadExclude(Node n) { none() }
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
@@ -58,7 +46,6 @@ module Consistency {
|
||||
n instanceof RelevantNode and
|
||||
c = count(nodeGetEnclosingCallable(n)) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
|
||||
msg = "Node should have one enclosing callable but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -79,7 +66,6 @@ module Consistency {
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
|
||||
msg = "Node should have one location but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -90,8 +76,7 @@ module Consistency {
|
||||
strictcount(Node n |
|
||||
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
|
||||
)
|
||||
) and
|
||||
msg = "Nodes without location: " + c
|
||||
)
|
||||
@@ -187,7 +172,6 @@ module Consistency {
|
||||
|
||||
query predicate reverseRead(Node n, string msg) {
|
||||
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
||||
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the `requests` PyPI package.
|
||||
*
|
||||
* See
|
||||
* - https://pypi.org/project/requests/
|
||||
* - https://docs.python-requests.org/en/latest/
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.dataflow.new.TaintTracking
|
||||
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
|
||||
private import semmle.python.frameworks.Stdlib
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides models for the `requests` PyPI package.
|
||||
*
|
||||
* See
|
||||
* - https://pypi.org/project/requests/
|
||||
* - https://docs.python-requests.org/en/latest/
|
||||
*/
|
||||
private module Requests {
|
||||
private class OutgoingRequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||
string methodName;
|
||||
|
||||
OutgoingRequestCall() {
|
||||
methodName in [HTTP::httpVerbLower(), "request"] and
|
||||
(
|
||||
this = API::moduleImport("requests").getMember(methodName).getACall()
|
||||
or
|
||||
exists(API::Node moduleExporting, API::Node sessionInstance |
|
||||
moduleExporting in [
|
||||
API::moduleImport("requests"), //
|
||||
API::moduleImport("requests").getMember("sessions")
|
||||
] and
|
||||
sessionInstance = moduleExporting.getMember(["Session", "session"]).getReturn()
|
||||
|
|
||||
this = sessionInstance.getMember(methodName).getACall()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result = this.getArgByName("url")
|
||||
or
|
||||
not methodName = "request" and
|
||||
result = this.getArg(0)
|
||||
or
|
||||
methodName = "request" and
|
||||
result = this.getArg(1)
|
||||
}
|
||||
|
||||
/** Gets the `verify` argument to this outgoing requests call. */
|
||||
DataFlow::Node getVerifyArg() { result = this.getArgByName("verify") }
|
||||
|
||||
override predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
disablingNode = this.getVerifyArg() and
|
||||
argumentOrigin = verifyArgBacktracker(disablingNode) and
|
||||
argumentOrigin.asExpr().(ImmutableLiteral).booleanValue() = false and
|
||||
not argumentOrigin.asExpr() instanceof None
|
||||
}
|
||||
|
||||
override string getFramework() { result = "requests" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra taint propagation for outgoing requests calls,
|
||||
* to ensure that responses to user-controlled URL are tainted.
|
||||
*/
|
||||
private class OutgoingRequestCallTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
nodeFrom = nodeTo.(OutgoingRequestCall).getAUrlPart()
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets a back-reference to the verify argument `arg`. */
|
||||
private DataFlow::TypeTrackingNode verifyArgBacktracker(
|
||||
DataFlow::TypeBackTracker t, DataFlow::Node arg
|
||||
) {
|
||||
t.start() and
|
||||
arg = any(OutgoingRequestCall c).getVerifyArg() and
|
||||
result = arg.getALocalSource()
|
||||
or
|
||||
exists(DataFlow::TypeBackTracker t2 | result = verifyArgBacktracker(t2, arg).backtrack(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a back-reference to the verify argument `arg`. */
|
||||
private DataFlow::LocalSourceNode verifyArgBacktracker(DataFlow::Node arg) {
|
||||
result = verifyArgBacktracker(DataFlow::TypeBackTracker::end(), arg)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Response
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* Provides models for the `requests.models.Response` class
|
||||
*
|
||||
* See https://docs.python-requests.org/en/latest/api/#requests.Response.
|
||||
*/
|
||||
module Response {
|
||||
/** Gets a reference to the `requests.models.Response` class. */
|
||||
private API::Node classRef() {
|
||||
result = API::moduleImport("requests").getMember("models").getMember("Response")
|
||||
or
|
||||
result = API::moduleImport("requests").getMember("Response")
|
||||
}
|
||||
|
||||
/**
|
||||
* A source of instances of `requests.models.Response`, 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 `Response::instance()` to get references to instances of `requests.models.Response`.
|
||||
*/
|
||||
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
|
||||
|
||||
/** A direct instantiation of `requests.models.Response`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
|
||||
ClassInstantiation() { this = classRef().getACall() }
|
||||
}
|
||||
|
||||
/** Return value from making a reuqest. */
|
||||
private class RequestReturnValue extends InstanceSource, DataFlow::Node {
|
||||
RequestReturnValue() { this = any(OutgoingRequestCall c) }
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `requests.models.Response`. */
|
||||
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 `requests.models.Response`. */
|
||||
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
|
||||
/**
|
||||
* Taint propagation for `requests.models.Response`.
|
||||
*/
|
||||
private class InstanceTaintSteps extends InstanceTaintStepsHelper {
|
||||
InstanceTaintSteps() { this = "requests.models.Response" }
|
||||
|
||||
override DataFlow::Node getInstance() { result = instance() }
|
||||
|
||||
override string getAttributeName() {
|
||||
result in ["text", "content", "raw", "links", "cookies", "headers"]
|
||||
}
|
||||
|
||||
override string getMethodName() { result in ["json", "iter_content", "iter_lines"] }
|
||||
|
||||
override string getAsyncMethodName() { none() }
|
||||
}
|
||||
|
||||
/** An attribute read that is a file-like instance. */
|
||||
private class FileLikeInstances extends Stdlib::FileLikeObject::InstanceSource {
|
||||
FileLikeInstances() {
|
||||
this.(DataFlow::AttrRead).getObject() = instance() and
|
||||
this.(DataFlow::AttrRead).getAttributeName() = "raw"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2091,201 +2091,6 @@ private module StdlibPrivate {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// http.client (Python 3)
|
||||
// httplib (Python 2)
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* Provides models for the `http.client.HTTPConnection` and `HTTPSConnection` classes
|
||||
*
|
||||
* See
|
||||
* - https://docs.python.org/3.10/library/http.client.html#http.client.HTTPConnection
|
||||
* - https://docs.python.org/3.10/library/http.client.html#http.client.HTTPSConnection
|
||||
* - https://docs.python.org/2.7/library/httplib.html#httplib.HTTPConnection
|
||||
* - https://docs.python.org/2.7/library/httplib.html#httplib.HTTPSConnection
|
||||
*/
|
||||
module HTTPConnection {
|
||||
/** Gets a reference to the `http.client.HTTPConnection` class. */
|
||||
private API::Node classRef() {
|
||||
exists(string className | className in ["HTTPConnection", "HTTPSConnection"] |
|
||||
// Python 3
|
||||
result = API::moduleImport("http").getMember("client").getMember(className)
|
||||
or
|
||||
// Python 2
|
||||
result = API::moduleImport("httplib").getMember(className)
|
||||
or
|
||||
result =
|
||||
API::moduleImport("six").getMember("moves").getMember("http_client").getMember(className)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A source of instances of `http.client.HTTPConnection`, 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 `HTTPConnection::instance()` to get references to instances of `http.client.HTTPConnection`.
|
||||
*/
|
||||
abstract class InstanceSource extends DataFlow::LocalSourceNode {
|
||||
/** Gets the argument that specified the host, if any. */
|
||||
abstract DataFlow::Node getHostArgument();
|
||||
}
|
||||
|
||||
/** A direct instantiation of `http.client.HTTPConnection`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
|
||||
ClassInstantiation() { this = classRef().getACall() }
|
||||
|
||||
override DataFlow::Node getHostArgument() {
|
||||
result in [this.getArg(0), this.getArgByName("host")]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to an instance of `http.client.HTTPConnection`,
|
||||
* that was instantiated with host argument `hostArg`.
|
||||
*/
|
||||
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t, DataFlow::Node hostArg) {
|
||||
t.start() and
|
||||
hostArg = result.(InstanceSource).getHostArgument()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = instance(t2, hostArg).track(t2, t))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to an instance of `http.client.HTTPConnection`,
|
||||
* that was instantiated with host argument `hostArg`.
|
||||
*/
|
||||
DataFlow::Node instance(DataFlow::Node hostArg) {
|
||||
instance(DataFlow::TypeTracker::end(), hostArg).flowsTo(result)
|
||||
}
|
||||
|
||||
/** A method call on a HTTPConnection that sends off a request */
|
||||
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::MethodCallNode {
|
||||
RequestCall() { this.calls(instance(_), ["request", "_send_request", "putrequest"]) }
|
||||
|
||||
DataFlow::Node getUrlArg() { result in [this.getArg(1), this.getArgByName("url")] }
|
||||
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result = this.getUrlArg()
|
||||
or
|
||||
this.getObject() = instance(result)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "http.client.HTTP[S]Connection" }
|
||||
|
||||
override predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
// TODO: Proper alerting of insecure verification settings on SSLContext.
|
||||
// Because that is not restricted to HTTP[S]Connection usage, we need something
|
||||
// more general, and I would like to tackle that in future PR.
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to the `getresponse` method. */
|
||||
private class HttpConnectionGetResponseCall extends DataFlow::MethodCallNode,
|
||||
HTTPResponse::InstanceSource {
|
||||
HttpConnectionGetResponseCall() { this.calls(instance(_), "getresponse") }
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra taint propagation for `http.client.HTTPConnection`,
|
||||
* to ensure that responses to user-controlled URL are tainted.
|
||||
*/
|
||||
private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// constructor
|
||||
exists(InstanceSource instanceSource |
|
||||
nodeFrom = instanceSource.getHostArgument() and
|
||||
nodeTo = instanceSource
|
||||
)
|
||||
or
|
||||
// a request method
|
||||
exists(RequestCall call |
|
||||
nodeFrom = call.getUrlArg() and
|
||||
nodeTo.(DataFlow::PostUpdateNode).getPreUpdateNode() = call.getObject()
|
||||
)
|
||||
or
|
||||
// `getresponse` call
|
||||
exists(HttpConnectionGetResponseCall call |
|
||||
nodeFrom = call.getObject() and
|
||||
nodeTo = call
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides models for the `http.client.HTTPResponse` class
|
||||
*
|
||||
* See
|
||||
* - https://docs.python.org/3.10/library/http.client.html#httpresponse-objects
|
||||
* - https://docs.python.org/3/library/http.client.html#http.client.HTTPResponse.
|
||||
*/
|
||||
module HTTPResponse {
|
||||
/** Gets a reference to the `http.client.HTTPResponse` class. */
|
||||
private API::Node classRef() {
|
||||
result = API::moduleImport("http").getMember("client").getMember("HTTPResponse")
|
||||
}
|
||||
|
||||
/**
|
||||
* A source of instances of `http.client.HTTPResponse`, extend this class to model new instances.
|
||||
*
|
||||
* A `http.client.HTTPResponse` is itself a file-like object.
|
||||
*
|
||||
* 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 `HTTPResponse::instance()` to get references to instances of `http.client.HTTPResponse`.
|
||||
*/
|
||||
abstract class InstanceSource extends Stdlib::FileLikeObject::InstanceSource,
|
||||
DataFlow::LocalSourceNode { }
|
||||
|
||||
/** A direct instantiation of `http.client.HTTPResponse`. */
|
||||
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
|
||||
ClassInstantiation() { this = classRef().getACall() }
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `http.client.HTTPResponse`. */
|
||||
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 `http.client.HTTPResponse`. */
|
||||
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
|
||||
/**
|
||||
* Taint propagation for `http.client.HTTPResponse`.
|
||||
*/
|
||||
private class InstanceTaintSteps extends InstanceTaintStepsHelper {
|
||||
InstanceTaintSteps() { this = "http.client.HTTPResponse" }
|
||||
|
||||
override DataFlow::Node getInstance() { result = instance() }
|
||||
|
||||
override string getAttributeName() { result in ["headers", "msg", "reason", "url"] }
|
||||
|
||||
override string getMethodName() { result in ["getheader", "getheaders", "info", "geturl",] }
|
||||
|
||||
override string getAsyncMethodName() { none() }
|
||||
}
|
||||
|
||||
/** An attribute read that is a HTTPMessage instance. */
|
||||
private class HTTPMessageInstances extends Stdlib::HTTPMessage::InstanceSource {
|
||||
HTTPMessageInstances() {
|
||||
this.(DataFlow::AttrRead).accesses(instance(), ["headers", "msg"])
|
||||
or
|
||||
this.(DataFlow::MethodCallNode).calls(instance(), "info")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// sqlite3
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -382,7 +382,7 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod
|
||||
/**
|
||||
* Class representing bound-methods.
|
||||
* Note that built-in methods, such as `[].append` are also represented as bound-methods.
|
||||
* Although built-in methods and bound-methods are distinct classes in CPython, their behavior
|
||||
* Although built-in methods and bound-methods are distinct classes in CPython, their behaviour
|
||||
* is the same and we treat them identically.
|
||||
*/
|
||||
class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting "Server-side request forgery" vulnerabilities.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `ServerSideRequestForgery::Configuration` is needed, otherwise
|
||||
* `ServerSideRequestForgeryCustomizations` should be imported instead.
|
||||
*/
|
||||
|
||||
private import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
import semmle.python.Concepts
|
||||
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting "Server-side request forgery" vulnerabilities.
|
||||
*
|
||||
* This configuration has a sanitizer to limit results to cases where attacker has full control of URL.
|
||||
* See `PartialServerSideRequestForgery` for a variant without this requirement.
|
||||
*
|
||||
* You should use the `partOfFullyControlledRequest` to only select results where all
|
||||
* URL parts are fully controlled.
|
||||
*/
|
||||
module FullServerSideRequestForgery {
|
||||
import ServerSideRequestForgeryCustomizations::ServerSideRequestForgery
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for detecting "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "FullServerSideRequestForgery" }
|
||||
|
||||
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
|
||||
or
|
||||
node instanceof FullUrlControlSanitizer
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all URL parts of `request` is fully user controlled.
|
||||
*/
|
||||
predicate fullyControlledRequest(HTTP::Client::Request request) {
|
||||
exists(FullServerSideRequestForgery::Configuration fullConfig |
|
||||
forall(DataFlow::Node urlPart | urlPart = request.getAUrlPart() |
|
||||
fullConfig.hasFlow(_, urlPart)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a taint-tracking configuration for detecting "Server-side request forgery" vulnerabilities.
|
||||
*
|
||||
* This configuration has results, even when the attacker does not have full control over the URL.
|
||||
* See `FullServerSideRequestForgery` for variant that has this requirement.
|
||||
*/
|
||||
module PartialServerSideRequestForgery {
|
||||
import ServerSideRequestForgeryCustomizations::ServerSideRequestForgery
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for detecting "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "PartialServerSideRequestForgery" }
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for detecting
|
||||
* "Server-side request forgery"
|
||||
* 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
|
||||
* "Server-side request forgery"
|
||||
* vulnerabilities, as well as extension points for adding your own.
|
||||
*/
|
||||
module ServerSideRequestForgery {
|
||||
/**
|
||||
* A data flow source for "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the request this sink belongs to.
|
||||
*/
|
||||
abstract HTTP::Client::Request getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer for "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for "Server-side request forgery" vulnerabilities,
|
||||
* that ensures the attacker does not have full control of the URL. (that is, might
|
||||
* still be able to control path or query parameters).
|
||||
*/
|
||||
abstract class FullUrlControlSanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer guard for "Server-side request forgery" vulnerabilities.
|
||||
*/
|
||||
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
|
||||
|
||||
/**
|
||||
* A source of remote user input, considered as a flow source.
|
||||
*/
|
||||
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
|
||||
|
||||
/** The URL of an HTTP request, considered as a sink. */
|
||||
class HttpRequestUrlAsSink extends Sink {
|
||||
HTTP::Client::Request req;
|
||||
|
||||
HttpRequestUrlAsSink() {
|
||||
req.getAUrlPart() = this and
|
||||
// if we extract the stdlib code for HTTPConnection, we will also find calls that
|
||||
// make requests within the HTTPConnection implementation -- for example the
|
||||
// `request` method calls the `_send_request` method internally. So without this
|
||||
// extra bit of code, we would give alerts within the HTTPConnection
|
||||
// implementation as well, which is just annoying.
|
||||
//
|
||||
// Notice that we're excluding based on the request location, and not the URL part
|
||||
// location, since the URL part would be in user code for the scenario above.
|
||||
//
|
||||
// See comment for command injection sinks for more details.
|
||||
not req.getScope().getEnclosingModule().getName() in ["http.client", "httplib"]
|
||||
}
|
||||
|
||||
override HTTP::Client::Request getRequest() { result = req }
|
||||
}
|
||||
|
||||
/**
|
||||
* A comparison with a constant string, considered as a sanitizer-guard.
|
||||
*/
|
||||
class StringConstCompareAsSanitizerGuard extends SanitizerGuard, StringConstCompare { }
|
||||
|
||||
/**
|
||||
* A string construction (concat, format, f-string) where the left side is not
|
||||
* user-controlled.
|
||||
*
|
||||
* For all of these cases, we try to allow `http://` or `https://` on the left side
|
||||
* since that will still allow full URL control.
|
||||
*/
|
||||
class StringConstructionAsFullUrlControlSanitizer extends FullUrlControlSanitizer {
|
||||
StringConstructionAsFullUrlControlSanitizer() {
|
||||
// string concat
|
||||
exists(BinaryExprNode add |
|
||||
add.getOp() instanceof Add and
|
||||
add.getRight() = this.asCfgNode() and
|
||||
not add.getLeft().getNode().(StrConst).getText().toLowerCase() in ["http://", "https://"]
|
||||
)
|
||||
or
|
||||
// % formatting
|
||||
exists(BinaryExprNode fmt |
|
||||
fmt.getOp() instanceof Mod and
|
||||
fmt.getRight() = this.asCfgNode() and
|
||||
// detecting %-formatting is not super easy, so we simplify it to only handle
|
||||
// when there is a **single** substitution going on.
|
||||
not fmt.getLeft().getNode().(StrConst).getText().regexpMatch("^(?i)https?://%s[^%]*$")
|
||||
)
|
||||
or
|
||||
// arguments to a format call
|
||||
exists(DataFlow::MethodCallNode call, string httpPrefixRe |
|
||||
httpPrefixRe = "^(?i)https?://(?:(\\{\\})|\\{([0-9]+)\\}|\\{([^0-9].*)\\}).*$"
|
||||
|
|
||||
call.getMethodName() = "format" and
|
||||
(
|
||||
if call.getObject().asExpr().(StrConst).getText().regexpMatch(httpPrefixRe)
|
||||
then
|
||||
exists(string text | text = call.getObject().asExpr().(StrConst).getText() |
|
||||
// `http://{}...`
|
||||
exists(text.regexpCapture(httpPrefixRe, 1)) and
|
||||
this in [call.getArg(any(int i | i >= 1)), call.getArgByName(_)]
|
||||
or
|
||||
// `http://{123}...`
|
||||
exists(int safeArgIndex | safeArgIndex = text.regexpCapture(httpPrefixRe, 2).toInt() |
|
||||
this in [call.getArg(any(int i | i != safeArgIndex)), call.getArgByName(_)]
|
||||
)
|
||||
or
|
||||
// `http://{abc}...`
|
||||
exists(string safeArgName | safeArgName = text.regexpCapture(httpPrefixRe, 3) |
|
||||
this in [call.getArg(_), call.getArgByName(any(string s | s != safeArgName))]
|
||||
)
|
||||
)
|
||||
else this in [call.getArg(_), call.getArgByName(_)]
|
||||
)
|
||||
)
|
||||
or
|
||||
// f-string
|
||||
exists(Fstring fstring |
|
||||
if fstring.getValue(0).(StrConst).getText().toLowerCase() in ["http://", "https://"]
|
||||
then fstring.getValue(any(int i | i >= 2)) = this.asExpr()
|
||||
else fstring.getValue(any(int i | i >= 1)) = this.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<include src="ServerSideRequestForgery-start.inc.qhelp" />
|
||||
|
||||
<!-- query specific -->
|
||||
<p>This query covers full SSRF, to find partial SSRF use the <code>py/partial-ssrf</code> query.</p>
|
||||
</overview>
|
||||
<include src="ServerSideRequestForgery-end.inc.qhelp" />
|
||||
</qhelp>
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* @name Full server-side request forgery
|
||||
* @description Making a network request to a URL that is fully user-controlled allows for request forgery attacks.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.1
|
||||
* @precision high
|
||||
* @id py/full-ssrf
|
||||
* @tags security
|
||||
* external/cwe/cwe-918
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.dataflow.ServerSideRequestForgery
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from
|
||||
FullServerSideRequestForgery::Configuration fullConfig, DataFlow::PathNode source,
|
||||
DataFlow::PathNode sink, HTTP::Client::Request request
|
||||
where
|
||||
request = sink.getNode().(FullServerSideRequestForgery::Sink).getRequest() and
|
||||
fullConfig.hasFlowPath(source, sink) and
|
||||
fullyControlledRequest(request)
|
||||
select request, source, sink, "The full URL of this request depends on $@.", source.getNode(),
|
||||
"a user-provided value"
|
||||
@@ -1,11 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<include src="ServerSideRequestForgery-start.inc.qhelp" />
|
||||
|
||||
<!-- query specific -->
|
||||
<p>This query covers partial SSRF, to find full SSRF use the <code>py/full-ssrf</code> query.</p>
|
||||
</overview>
|
||||
<include src="ServerSideRequestForgery-end.inc.qhelp" />
|
||||
</qhelp>
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* @name Partial server-side request forgery
|
||||
* @description Making a network request to a URL that is partially user-controlled allows for request forgery attacks.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.1
|
||||
* @precision medium
|
||||
* @id py/partial-ssrf
|
||||
* @tags security
|
||||
* external/cwe/cwe-918
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.dataflow.ServerSideRequestForgery
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from
|
||||
PartialServerSideRequestForgery::Configuration partialConfig, DataFlow::PathNode source,
|
||||
DataFlow::PathNode sink, HTTP::Client::Request request
|
||||
where
|
||||
request = sink.getNode().(PartialServerSideRequestForgery::Sink).getRequest() and
|
||||
partialConfig.hasFlowPath(source, sink) and
|
||||
not fullyControlledRequest(request)
|
||||
select request, source, sink, "Part of the URL of this request depends on $@.", source.getNode(),
|
||||
"a user-provided value"
|
||||
@@ -1,47 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<recommendation>
|
||||
|
||||
<p>To guard against SSRF attacks you should avoid putting user-provided input directly
|
||||
into a request URL. Instead, either maintain a list of authorized URLs on the server and choose
|
||||
from that list based on the input provided, or perform proper validation of the input.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>The following example shows code vulnerable to a full SSRF attack, because it
|
||||
uses untrusted input (HTTP request parameter) directly to construct a URL. By using
|
||||
<code>evil.com#</code> as the <code>target</code> value, the requested URL will be
|
||||
<code>https://evil.com#.example.com/data/</code>. It also shows how to remedy the
|
||||
problem by using the user input select a known fixed string.
|
||||
</p>
|
||||
|
||||
<sample src="examples/ServerSideRequestForgery_full.py" />
|
||||
|
||||
</example>
|
||||
<example>
|
||||
|
||||
<p>
|
||||
The following example shows code vulnerable to a partial SSRF attack, because it
|
||||
uses untrusted input (HTTP request parameter) directly to construct a URL. By
|
||||
using <code>../transfer-funds-to/123?amount=456</code> as the
|
||||
<code>user_id</code> value, the requested URL will be
|
||||
<code>https://api.example.com/transfer-funds-to/123?amount=456</code>. It also
|
||||
shows how to remedy the problem by validating the input.
|
||||
</p>
|
||||
|
||||
<sample src="examples/ServerSideRequestForgery_partial.py" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://owasp.org/www-community/attacks/Server_Side_Request_Forgery">OWASP SSRF article</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://portswigger.net/web-security/ssrf">PortSwigger SSRF article</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,31 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<fragment>
|
||||
<p>Directly incorporating user input into an HTTP request without validating the input
|
||||
can facilitate server-side request forgery (SSRF) attacks. In these attacks, the
|
||||
request may be changed, directed at a different server, or via a different
|
||||
protocol. This can allow the attacker to obtain sensitive information or perform
|
||||
actions with escalated privilege.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
We make a distinctions between how much of the URL an attacker can control:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Full SSRF</b>: where the full URL can be controlled.</li>
|
||||
<li><b>Partial SSRF</b>: where only part of the URL can be controlled, such as the
|
||||
path component of a URL to a hardcoded domain.</li>
|
||||
</ul>
|
||||
|
||||
<p></p>
|
||||
|
||||
<p>
|
||||
Partial control of a URL is often much harder to exploit. Therefore we have created a
|
||||
separate query for each of these.
|
||||
</p>
|
||||
|
||||
</fragment>
|
||||
</qhelp>
|
||||
@@ -1,15 +0,0 @@
|
||||
import requests
|
||||
from flask import Flask, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/full_ssrf")
|
||||
def full_ssrf():
|
||||
target = request.args["target"]
|
||||
|
||||
# BAD: user has full control of URL
|
||||
resp = request.get("https://" + target + ".example.com/data/")
|
||||
|
||||
# GOOD: `subdomain` is controlled by the server.
|
||||
subdomain = "europe" if target == "EU" else "world"
|
||||
resp = request.get("https://" + subdomain + ".example.com/data/")
|
||||
@@ -1,15 +0,0 @@
|
||||
import requests
|
||||
from flask import Flask, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/partial_ssrf")
|
||||
def partial_ssrf():
|
||||
user_id = request.args["user_id"]
|
||||
|
||||
# BAD: user can fully control the path component of the URL
|
||||
resp = requests.get("https://api.example.com/user_info/" + user_id)
|
||||
|
||||
if user_id.isalnum():
|
||||
# GOOD: user_id is restricted to be alpha-numeric, and cannot alter path component of URL
|
||||
resp = requests.get("https://api.example.com/user_info/" + user_id)
|
||||
@@ -475,31 +475,3 @@ class CryptographicOperationTest extends InlineExpectationsTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class HttpClientRequestTest extends InlineExpectationsTest {
|
||||
HttpClientRequestTest() { this = "HttpClientRequestTest" }
|
||||
|
||||
override string getARelevantTag() {
|
||||
result in ["clientRequestUrlPart", "clientRequestCertValidationDisabled"]
|
||||
}
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(HTTP::Client::Request req, DataFlow::Node url |
|
||||
url = req.getAUrlPart() and
|
||||
location = url.getLocation() and
|
||||
element = url.toString() and
|
||||
value = prettyNodeForInlineTest(url) and
|
||||
tag = "clientRequestUrlPart"
|
||||
)
|
||||
or
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(HTTP::Client::Request req |
|
||||
req.disablesCertificateValidation(_, _) and
|
||||
location = req.getLocation() and
|
||||
element = req.toString() and
|
||||
value = "" and
|
||||
tag = "clientRequestCertValidationDisabled"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
import python
|
||||
import experimental.meta.ConceptsTest
|
||||
@@ -1,3 +0,0 @@
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
@@ -1 +0,0 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
@@ -1,55 +0,0 @@
|
||||
import requests
|
||||
|
||||
from flask import Flask, request
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route("/taint_test") # $ routeSetup="/taint_test"
|
||||
def test_taint(): # $ requestHandler
|
||||
url = request.args['untrusted_input']
|
||||
|
||||
# response from a request to a user-controlled URL should be considered
|
||||
# user-controlled as well.
|
||||
resp = requests.get(url) # $ clientRequestUrlPart=url
|
||||
|
||||
requests.Response
|
||||
requests.models.Response
|
||||
|
||||
ensure_tainted(
|
||||
url, # $ tainted
|
||||
# see https://docs.python-requests.org/en/latest/api/#requests.Response
|
||||
resp, # $ tainted
|
||||
resp.text, # $ tainted
|
||||
resp.content, # $ tainted
|
||||
resp.json(), # $ tainted
|
||||
|
||||
# file-like
|
||||
resp.raw, # $ tainted
|
||||
resp.raw.read(), # $ tainted
|
||||
|
||||
resp.links, # $ tainted
|
||||
resp.links['key'], # $ tainted
|
||||
resp.links.get('key'), # $ tainted
|
||||
|
||||
resp.cookies, # $ tainted
|
||||
resp.cookies['key'], # $ tainted
|
||||
resp.cookies.get('key'), # $ tainted
|
||||
|
||||
resp.headers, # $ tainted
|
||||
resp.headers['key'], # $ tainted
|
||||
resp.headers.get('key'), # $ tainted
|
||||
)
|
||||
|
||||
for content_chunk in resp.iter_content():
|
||||
ensure_tainted(content_chunk) # $ tainted
|
||||
|
||||
for line in resp.iter_lines():
|
||||
ensure_tainted(line) # $ tainted
|
||||
|
||||
# for now, we don't assume that the response to ANY outgoing request is a remote
|
||||
# flow source, since this could lead to FPs.
|
||||
# TODO: investigate whether we should consider this a remote flow source.
|
||||
trusted_url = "https://internal-api-that-i-trust.com"
|
||||
resp = requests.get(trusted_url) # $ clientRequestUrlPart=trusted_url
|
||||
ensure__not_tainted(resp)
|
||||
@@ -1,50 +0,0 @@
|
||||
import requests
|
||||
|
||||
resp = requests.get("url") # $ clientRequestUrlPart="url"
|
||||
resp = requests.get(url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
resp = requests.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
with requests.Session() as session:
|
||||
resp = session.get("url") # $ clientRequestUrlPart="url"
|
||||
resp = session.request(method="GET", url="url") # $ clientRequestUrlPart="url"
|
||||
|
||||
s = requests.Session()
|
||||
resp = s.get("url") # $ clientRequestUrlPart="url"
|
||||
|
||||
s = requests.session()
|
||||
resp = s.get("url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# test full import path for Session
|
||||
with requests.sessions.Session() as session:
|
||||
resp = session.get("url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# Low level access
|
||||
req = requests.Request("GET", "url") # $ MISSING: clientRequestUrlPart="url"
|
||||
resp = s.send(req.prepare())
|
||||
|
||||
# other methods than GET
|
||||
resp = requests.post("url") # $ clientRequestUrlPart="url"
|
||||
resp = requests.patch("url") # $ clientRequestUrlPart="url"
|
||||
resp = requests.options("url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# ==============================================================================
|
||||
# Disabling certificate validation
|
||||
# ==============================================================================
|
||||
|
||||
resp = requests.get("url", verify=False) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
def make_get(verify_arg):
|
||||
resp = requests.get("url", verify=verify_arg) # $ clientRequestUrlPart="url" clientRequestCertValidationDisabled
|
||||
|
||||
make_get(False)
|
||||
|
||||
|
||||
with requests.Session() as session:
|
||||
# see https://github.com/psf/requests/blob/39d0fdd9096f7dceccbc8f82e1eda7dd64717a8e/requests/sessions.py#L621
|
||||
session.verify = False
|
||||
resp = session.get("url") # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
resp = session.get("url", verify=True) # $ clientRequestUrlPart="url"
|
||||
|
||||
req = requests.Request("GET", "url") # $ MISSING: clientRequestUrlPart="url"
|
||||
resp = session.send(req.prepare()) # $ MISSING: clientRequestCertValidationDisabled
|
||||
@@ -1,170 +0,0 @@
|
||||
import sys
|
||||
import ssl
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY2:
|
||||
from httplib import HTTPConnection, HTTPSConnection
|
||||
if PY3:
|
||||
from http.client import HTTPConnection, HTTPSConnection
|
||||
|
||||
|
||||
# NOTE: the URL may be relative to host, or may be full URL.
|
||||
conn = HTTPConnection("example.com") # $ clientRequestUrlPart="example.com"
|
||||
conn.request("GET", "/") # $ clientRequestUrlPart="/"
|
||||
url = "http://example.com/"
|
||||
conn.request("GET", url) # $ clientRequestUrlPart=url
|
||||
|
||||
# kwargs
|
||||
conn = HTTPConnection(host="example.com") # $ clientRequestUrlPart="example.com"
|
||||
conn.request(method="GET", url="/") # $ clientRequestUrlPart="/"
|
||||
|
||||
# using internal method... you shouldn't but you can
|
||||
conn._send_request("GET", "url", body=None, headers={}, encode_chunked=False) # $ clientRequestUrlPart="url"
|
||||
|
||||
# low level sending of request
|
||||
conn.putrequest("GET", "url") # $ clientRequestUrlPart="url"
|
||||
conn.putheader("X-Foo", "value")
|
||||
conn.endheaders(message_body=None)
|
||||
|
||||
# HTTPS
|
||||
conn = HTTPSConnection("host") # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# six aliases
|
||||
import six
|
||||
|
||||
conn = six.moves.http_client.HTTPConnection("host") # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
conn = six.moves.http_client.HTTPSConnection("host") # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# ==============================================================================
|
||||
# Certificate validation disabled
|
||||
# ==============================================================================
|
||||
|
||||
# default SSL context is the one given by `_create_default_https_context`
|
||||
context = ssl._create_default_https_context()
|
||||
assert context.check_hostname == True
|
||||
assert context.verify_mode == ssl.CERT_REQUIRED
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# `_create_default_https_context` is currently just an alias for `create_default_context`
|
||||
# which creates a context for SERVER_AUTH purpose.
|
||||
context = ssl.create_default_context()
|
||||
assert context.check_hostname == True
|
||||
assert context.verify_mode == ssl.CERT_REQUIRED
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# however, if you supply your own SSLContext, you need to set it manually
|
||||
context = ssl.SSLContext()
|
||||
assert context.check_hostname == False
|
||||
assert context.verify_mode == ssl.CERT_NONE
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
|
||||
# and if you misunderstood whether to use server/client in the purpose, you will also
|
||||
# get a context without hostname verification.
|
||||
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
assert context.check_hostname == False
|
||||
assert context.verify_mode == ssl.CERT_NONE
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
|
||||
# NOTICE that current documentation says
|
||||
#
|
||||
# > Enabling hostname checking automatically sets verify_mode from CERT_NONE to
|
||||
# > CERT_REQUIRED. It cannot be set back to CERT_NONE as long as hostname checking is
|
||||
# > enabled.
|
||||
# - https://docs.python.org/3.10/library/ssl.html#ssl.SSLContext.check_hostname
|
||||
|
||||
context = ssl.SSLContext()
|
||||
context.check_hostname = True
|
||||
assert context.verify_mode == ssl.CERT_REQUIRED
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
|
||||
# only setting verify_mode is not enough, since check_hostname is not enabled
|
||||
|
||||
context = ssl.SSLContext()
|
||||
context.verify_mode = ssl.CERT_REQUIRED
|
||||
assert context.check_hostname == False
|
||||
|
||||
conn = HTTPSConnection("host", context=context) # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url" MISSING: clientRequestCertValidationDisabled
|
||||
|
||||
# ==============================================================================
|
||||
# taint test
|
||||
# ==============================================================================
|
||||
|
||||
from flask import request
|
||||
|
||||
def taint_test():
|
||||
host = request.args['host']
|
||||
url = request.args['url']
|
||||
|
||||
conn = HTTPConnection(host) # $ clientRequestUrlPart=host
|
||||
conn.request("GET", url) # $ clientRequestUrlPart=url
|
||||
|
||||
resp = conn.getresponse()
|
||||
|
||||
ensure_tainted(
|
||||
# see
|
||||
# https://docs.python.org/3.10/library/http.client.html#httpresponse-objects
|
||||
# https://docs.python.org/3/library/http.client.html#http.client.HTTPResponse
|
||||
|
||||
# a HTTPResponse itself is file-like
|
||||
resp, # $ tainted
|
||||
resp.read(), # $ tainted
|
||||
|
||||
resp.getheader("name"), # $ tainted
|
||||
resp.getheaders(), # $ tainted
|
||||
|
||||
# http.client.HTTPMessage
|
||||
resp.headers, # $ tainted
|
||||
resp.headers.get_all(), # $ tainted
|
||||
|
||||
# Alias for .headers
|
||||
# http.client.HTTPMessage
|
||||
resp.msg, # $ tainted
|
||||
resp.msg.get_all(), # $ tainted
|
||||
|
||||
# Alias for .headers
|
||||
resp.info(), # $ tainted
|
||||
resp.info().get_all(), # $ tainted
|
||||
|
||||
# although this would usually be the textual version of the status
|
||||
# ("OK" for 200), it is possible to put your own evil data in here.
|
||||
resp.reason, # $ tainted
|
||||
|
||||
# the URL of the recourse that was visited, if redirects were followed.
|
||||
# I don't see any reason this could not contain evil data.
|
||||
resp.url, # $ tainted
|
||||
resp.geturl(), # $ tainted
|
||||
)
|
||||
|
||||
ensure_not_tainted(
|
||||
resp.status,
|
||||
resp.code,
|
||||
resp.getcode(),
|
||||
)
|
||||
|
||||
# check that only setting either host/url is enough to propagate taint
|
||||
conn = HTTPConnection("host") # $ clientRequestUrlPart="host"
|
||||
conn.request("GET", url) # $ clientRequestUrlPart=url
|
||||
resp = conn.getresponse()
|
||||
ensure_tainted(resp) # $ tainted
|
||||
|
||||
conn = HTTPConnection(host) # $ clientRequestUrlPart=host
|
||||
conn.request("GET", "url") # $ clientRequestUrlPart="url"
|
||||
resp = conn.getresponse()
|
||||
ensure_tainted(resp) # $ tainted
|
||||
@@ -1,274 +0,0 @@
|
||||
edges
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:8:17:8:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:13:18:13:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:13:18:13:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:19:18:19:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:19:18:19:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:8:17:8:23 | ControlFlowNode for request | full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute | full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:38:17:38:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:42:18:42:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:42:18:42:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:45:18:45:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:45:18:45:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:51:18:51:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:51:18:51:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:54:18:54:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:54:18:54:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:38:17:38:23 | ControlFlowNode for request | full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute | full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:58:17:58:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:62:18:62:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:62:18:62:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:65:18:65:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:65:18:65:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute | full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript | full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple | full_partial_test.py:68:18:68:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:72:17:72:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:76:18:76:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:76:18:76:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:79:18:79:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:79:18:79:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:72:17:72:23 | ControlFlowNode for request | full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute | full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:86:18:86:24 | ControlFlowNode for request | full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute | full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript | full_partial_test.py:89:18:89:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:92:18:92:24 | ControlFlowNode for request | full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute | full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript | full_partial_test.py:95:18:95:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:98:18:98:24 | ControlFlowNode for request | full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute | full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript | full_partial_test.py:101:18:101:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:104:18:104:24 | ControlFlowNode for request | full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute | full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript | full_partial_test.py:107:18:107:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:110:18:110:24 | ControlFlowNode for request | full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute | full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript | full_partial_test.py:116:18:116:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:119:18:119:24 | ControlFlowNode for request | full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute | full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript | full_partial_test.py:122:18:122:20 | ControlFlowNode for url |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:11:18:11:24 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:11:18:11:24 | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:11:18:11:24 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute | test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | test_http_client.py:33:25:33:28 | ControlFlowNode for path |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | test_http_client.py:37:25:37:28 | ControlFlowNode for path |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:6:18:6:29 | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:6:18:6:29 | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | test_requests.py:6:18:6:48 | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | test_requests.py:6:18:6:48 | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | test_requests.py:8:18:8:27 | ControlFlowNode for user_input |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | test_requests.py:8:18:8:27 | ControlFlowNode for user_input |
|
||||
nodes
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:8:17:8:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:13:18:13:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:13:18:13:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:19:18:19:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:19:18:19:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:23:18:23:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:23:18:23:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:38:17:38:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:42:18:42:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:42:18:42:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:45:18:45:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:45:18:45:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:48:18:48:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:48:18:48:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:51:18:51:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:51:18:51:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:68:18:68:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:72:17:72:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:79:18:79:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:79:18:79:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:82:18:82:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:82:18:82:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:86:18:86:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:89:18:89:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:92:18:92:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:95:18:95:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:98:18:98:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:101:18:101:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:104:18:104:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:107:18:107:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:110:18:110:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:116:18:116:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:119:18:119:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:122:18:122:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:33:25:33:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| test_http_client.py:37:25:37:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
subpaths
|
||||
#select
|
||||
| full_partial_test.py:10:5:10:28 | ControlFlowNode for Attribute() | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | The full URL of this request depends on $@. | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:13:5:13:21 | ControlFlowNode for Attribute() | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:13:18:13:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:19:5:19:21 | ControlFlowNode for Attribute() | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:19:18:19:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:23:5:23:21 | ControlFlowNode for Attribute() | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:23:18:23:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:7:18:7:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:42:5:42:21 | ControlFlowNode for Attribute() | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:42:18:42:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:45:5:45:21 | ControlFlowNode for Attribute() | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:45:18:45:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:48:5:48:21 | ControlFlowNode for Attribute() | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:48:18:48:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:51:5:51:21 | ControlFlowNode for Attribute() | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:51:18:51:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:54:5:54:21 | ControlFlowNode for Attribute() | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:54:18:54:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:37:18:37:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:62:5:62:21 | ControlFlowNode for Attribute() | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:62:18:62:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:65:5:65:21 | ControlFlowNode for Attribute() | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:65:18:65:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:76:5:76:21 | ControlFlowNode for Attribute() | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:76:18:76:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:79:5:79:21 | ControlFlowNode for Attribute() | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:79:18:79:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:82:5:82:21 | ControlFlowNode for Attribute() | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:82:18:82:20 | ControlFlowNode for url | The full URL of this request depends on $@. | full_partial_test.py:71:18:71:24 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:14:5:14:36 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | The full URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:14:5:14:36 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:14:5:14:36 | ControlFlowNode for Attribute() | test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on $@. | test_http_client.py:10:19:10:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:19:5:19:36 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | The full URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:19:5:19:36 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:19:5:19:36 | ControlFlowNode for Attribute() | test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | The full URL of this request depends on $@. | test_http_client.py:10:19:10:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_requests.py:8:5:8:28 | ControlFlowNode for Attribute() | test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:8:18:8:27 | ControlFlowNode for user_input | The full URL of this request depends on $@. | test_requests.py:6:18:6:24 | ControlFlowNode for request | a user-provided value |
|
||||
@@ -1 +0,0 @@
|
||||
Security/CWE-918/FullServerSideRequestForgery.ql
|
||||
@@ -1,271 +0,0 @@
|
||||
edges
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:8:17:8:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:13:18:13:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:13:18:13:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:19:18:19:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:19:18:19:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:8:17:8:23 | ControlFlowNode for request | full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute | full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript | full_partial_test.py:23:18:23:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:38:17:38:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:42:18:42:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:42:18:42:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:45:18:45:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:45:18:45:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:51:18:51:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:51:18:51:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:54:18:54:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | full_partial_test.py:54:18:54:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:38:17:38:23 | ControlFlowNode for request | full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute | full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript | full_partial_test.py:48:18:48:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:58:17:58:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:62:18:62:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:62:18:62:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:65:18:65:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:65:18:65:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute | full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript | full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple | full_partial_test.py:68:18:68:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:72:17:72:23 | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:76:18:76:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:76:18:76:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:79:18:79:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:79:18:79:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:72:17:72:23 | ControlFlowNode for request | full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute | full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript | full_partial_test.py:82:18:82:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:86:18:86:24 | ControlFlowNode for request | full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute | full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript | full_partial_test.py:89:18:89:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:92:18:92:24 | ControlFlowNode for request | full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute | full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript | full_partial_test.py:95:18:95:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:98:18:98:24 | ControlFlowNode for request | full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute | full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript | full_partial_test.py:101:18:101:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:104:18:104:24 | ControlFlowNode for request | full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute | full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript | full_partial_test.py:107:18:107:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:110:18:110:24 | ControlFlowNode for request | full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute | full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript | full_partial_test.py:116:18:116:20 | ControlFlowNode for url |
|
||||
| full_partial_test.py:119:18:119:24 | ControlFlowNode for request | full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute | full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript | full_partial_test.py:122:18:122:20 | ControlFlowNode for url |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:25 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:11:18:11:24 | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:11:18:11:24 | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:11:18:11:24 | ControlFlowNode for request | test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute | test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | test_http_client.py:33:25:33:28 | ControlFlowNode for path |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | test_http_client.py:37:25:37:28 | ControlFlowNode for path |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:6:18:6:29 | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | test_requests.py:6:18:6:29 | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | test_requests.py:6:18:6:48 | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | test_requests.py:6:18:6:48 | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | test_requests.py:8:18:8:27 | ControlFlowNode for user_input |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | test_requests.py:8:18:8:27 | ControlFlowNode for user_input |
|
||||
nodes
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:7:18:7:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:8:17:8:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:8:17:8:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:8:17:8:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:10:18:10:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| full_partial_test.py:13:18:13:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:13:18:13:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:19:18:19:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:19:18:19:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:23:18:23:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:23:18:23:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:37:18:37:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:38:17:38:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:38:17:38:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:38:17:38:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:42:18:42:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:42:18:42:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:45:18:45:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:45:18:45:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:48:18:48:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:48:18:48:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:51:18:51:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:51:18:51:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:54:18:54:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:57:18:57:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:58:17:58:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:58:17:58:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:58:17:58:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:62:18:62:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:65:18:65:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:67:38:67:58 | ControlFlowNode for Tuple | semmle.label | ControlFlowNode for Tuple |
|
||||
| full_partial_test.py:68:18:68:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:71:18:71:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:72:17:72:23 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:72:17:72:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:72:17:72:41 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:76:18:76:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:79:18:79:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:79:18:79:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:82:18:82:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:82:18:82:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:86:18:86:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:86:18:86:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:86:18:86:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:89:18:89:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:92:18:92:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:92:18:92:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:92:18:92:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:95:18:95:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:98:18:98:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:98:18:98:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:98:18:98:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:101:18:101:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:104:18:104:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:104:18:104:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:104:18:104:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:107:18:107:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:110:18:110:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:110:18:110:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:110:18:110:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:116:18:116:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| full_partial_test.py:119:18:119:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| full_partial_test.py:119:18:119:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| full_partial_test.py:119:18:119:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| full_partial_test.py:122:18:122:20 | ControlFlowNode for url | semmle.label | ControlFlowNode for url |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:9:19:9:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:25 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:30 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:10:19:10:38 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:11:18:11:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_http_client.py:11:18:11:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_http_client.py:11:18:11:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:13:27:13:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:14:25:14:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:19:25:19:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | semmle.label | ControlFlowNode for unsafe_host |
|
||||
| test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | semmle.label | ControlFlowNode for unsafe_path |
|
||||
| test_http_client.py:33:25:33:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| test_http_client.py:37:25:37:28 | ControlFlowNode for path | semmle.label | ControlFlowNode for path |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_requests.py:6:18:6:24 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_requests.py:6:18:6:48 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
|
||||
| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
| test_requests.py:8:18:8:27 | ControlFlowNode for user_input | semmle.label | ControlFlowNode for user_input |
|
||||
subpaths
|
||||
#select
|
||||
| full_partial_test.py:68:5:68:21 | ControlFlowNode for Attribute() | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | full_partial_test.py:68:18:68:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:57:18:57:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:68:5:68:21 | ControlFlowNode for Attribute() | full_partial_test.py:58:17:58:23 | ControlFlowNode for request | full_partial_test.py:68:18:68:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:58:17:58:23 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:89:5:89:21 | ControlFlowNode for Attribute() | full_partial_test.py:86:18:86:24 | ControlFlowNode for request | full_partial_test.py:89:18:89:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:86:18:86:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:95:5:95:21 | ControlFlowNode for Attribute() | full_partial_test.py:92:18:92:24 | ControlFlowNode for request | full_partial_test.py:95:18:95:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:92:18:92:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:101:5:101:21 | ControlFlowNode for Attribute() | full_partial_test.py:98:18:98:24 | ControlFlowNode for request | full_partial_test.py:101:18:101:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:98:18:98:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:107:5:107:21 | ControlFlowNode for Attribute() | full_partial_test.py:104:18:104:24 | ControlFlowNode for request | full_partial_test.py:107:18:107:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:104:18:104:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:116:5:116:21 | ControlFlowNode for Attribute() | full_partial_test.py:110:18:110:24 | ControlFlowNode for request | full_partial_test.py:116:18:116:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:110:18:110:24 | ControlFlowNode for request | a user-provided value |
|
||||
| full_partial_test.py:122:5:122:21 | ControlFlowNode for Attribute() | full_partial_test.py:119:18:119:24 | ControlFlowNode for request | full_partial_test.py:122:18:122:20 | ControlFlowNode for url | Part of the URL of this request depends on $@. | full_partial_test.py:119:18:119:24 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:22:5:22:31 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:18:27:18:37 | ControlFlowNode for unsafe_host | Part of the URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:26:5:26:31 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:25:27:25:37 | ControlFlowNode for unsafe_host | Part of the URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:29:5:29:36 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | Part of the URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:29:5:29:36 | ControlFlowNode for Attribute() | test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:29:25:29:35 | ControlFlowNode for unsafe_path | Part of the URL of this request depends on $@. | test_http_client.py:10:19:10:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:33:5:33:29 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:33:25:33:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:33:5:33:29 | ControlFlowNode for Attribute() | test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:33:25:33:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:10:19:10:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:33:5:33:29 | ControlFlowNode for Attribute() | test_http_client.py:11:18:11:24 | ControlFlowNode for request | test_http_client.py:33:25:33:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:11:18:11:24 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:37:5:37:29 | ControlFlowNode for Attribute() | test_http_client.py:9:19:9:25 | ControlFlowNode for request | test_http_client.py:37:25:37:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:9:19:9:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:37:5:37:29 | ControlFlowNode for Attribute() | test_http_client.py:10:19:10:25 | ControlFlowNode for request | test_http_client.py:37:25:37:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:10:19:10:25 | ControlFlowNode for request | a user-provided value |
|
||||
| test_http_client.py:37:5:37:29 | ControlFlowNode for Attribute() | test_http_client.py:11:18:11:24 | ControlFlowNode for request | test_http_client.py:37:25:37:28 | ControlFlowNode for path | Part of the URL of this request depends on $@. | test_http_client.py:11:18:11:24 | ControlFlowNode for request | a user-provided value |
|
||||
@@ -1 +0,0 @@
|
||||
Security/CWE-918/PartialServerSideRequestForgery.ql
|
||||
@@ -1,122 +0,0 @@
|
||||
from flask import request
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
def full_ssrf():
|
||||
user_input = request.args['untrusted_input']
|
||||
query_val = request.args['query_val']
|
||||
|
||||
requests.get(user_input) # NOT OK -- user has full control
|
||||
|
||||
url = "https://" + user_input
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
# although the path `/foo` is added here, this can be circumvented such that the
|
||||
# final URL is `https://evil.com/#/foo" -- since the fragment (#) is not sent to the
|
||||
# server.
|
||||
url = "https://" + user_input + "/foo"
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
# this might seem like a dummy test, but it serves to check how our sanitizers work.
|
||||
url = "https://" + user_input + "/foo?key=" + query_val
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
# taint-steps are added as `fromNode -> toNode`, but when adding a sanitizer it's
|
||||
# currently only possible to so on either `fromNode` or `toNode` (either all edges in
|
||||
# and out, or just the edges in or out). The sanitizers for full URL control is applied
|
||||
# on the `fromNode`, since for `"https://{}/{}".format(user_input1, user_input2)` there
|
||||
# is still a valid taint-step for `user_input1` -- if we made `toNode` a sanitizer that
|
||||
# would also remove this flow that we actually want. When coupled with use-use flow,
|
||||
# this means that later uses of a sanitized value will no longer be tainted, so
|
||||
# `requests.get(user_input2)` would no longer give an alert. To overcome this problem,
|
||||
# we split these tests into multiple functions, so we do not get this use-use flow, and
|
||||
# therefore know we are able to see where the sanitizers are applied.
|
||||
|
||||
def full_ssrf_format():
|
||||
user_input = request.args['untrusted_input']
|
||||
query_val = request.args['query_val']
|
||||
|
||||
# using .format
|
||||
url = "https://{}".format(user_input)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://{}/foo".format(user_input)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://{}/foo?key={}".format(user_input, query_val)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://{x}".format(x=user_input)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://{1}".format(0, user_input)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
def full_ssrf_percent_format():
|
||||
user_input = request.args['untrusted_input']
|
||||
query_val = request.args['query_val']
|
||||
|
||||
# using %-formatting
|
||||
url = "https://%s" % user_input
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://%s/foo" % user_input
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = "https://%s/foo/key=%s" % (user_input, query_val)
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
def full_ssrf_f_strings():
|
||||
user_input = request.args['untrusted_input']
|
||||
query_val = request.args['query_val']
|
||||
|
||||
# using f-strings
|
||||
url = f"https://{user_input}"
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = f"https://{user_input}/foo"
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
url = f"https://{user_input}/foo?key={query_val}"
|
||||
requests.get(url) # NOT OK -- user has full control
|
||||
|
||||
|
||||
def partial_ssrf_1():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
url = "https://example.com/foo?" + user_input
|
||||
requests.get(url) # NOT OK -- user controls query parameters
|
||||
|
||||
def partial_ssrf_2():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
url = "https://example.com/" + user_input
|
||||
requests.get(url) # NOT OK -- user controls path
|
||||
|
||||
def partial_ssrf_3():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
url = "https://example.com/" + user_input
|
||||
requests.get(url) # NOT OK -- user controls path
|
||||
|
||||
def partial_ssrf_4():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
url = "https://example.com/foo#{}".format(user_input)
|
||||
requests.get(url) # NOT OK -- user contollred fragment
|
||||
|
||||
def partial_ssrf_5():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
# this is probably the least interesting one, since it's only the fragment that is
|
||||
# controlled
|
||||
|
||||
url = "https://example.com/foo#%s" % user_input
|
||||
requests.get(url) # NOT OK -- user contollred fragment
|
||||
|
||||
def partial_ssrf_6():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
url = f"https://example.com/foo#{user_input}"
|
||||
requests.get(url) # NOT OK -- user only controlled fragment
|
||||
@@ -1 +0,0 @@
|
||||
semmle-extractor-options: --lang=3 --max-import-depth=1
|
||||
@@ -1,37 +0,0 @@
|
||||
from flask import Flask, request
|
||||
|
||||
from http.client import HTTPConnection
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/ssrf_test") # $ routeSetup="/ssrf_test"
|
||||
def ssrf_test():
|
||||
unsafe_host = request.args["host"]
|
||||
unsafe_path = request.args["path"]
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
conn = HTTPConnection(unsafe_host)
|
||||
conn.request("GET", unsafe_path) # NOT OK -- user has full control
|
||||
|
||||
# Full SSRF variant, where there is ALSO made a request with fixed URL on the same
|
||||
# connection later on. This should not change anything on the overall SSRF alerts.
|
||||
conn = HTTPConnection(unsafe_host)
|
||||
conn.request("GET", unsafe_path) # NOT OK -- user has full control
|
||||
|
||||
# partial SSRF on SAME connection
|
||||
conn.request("GET", "/foo") # NOT OK -- user has control of host
|
||||
|
||||
# the rest are partial SSRF
|
||||
conn = HTTPConnection(unsafe_host)
|
||||
conn.request("GET", "/foo") # NOT OK -- user controlled domain
|
||||
|
||||
conn = HTTPConnection("example.com")
|
||||
conn.request("GET", unsafe_path) # NOT OK -- user controlled path
|
||||
|
||||
path = "foo?" + user_input
|
||||
conn = HTTPConnection("example.com")
|
||||
conn.request("GET", path) # NOT OK -- user controlled query parameters
|
||||
|
||||
path = "foo#" + user_input
|
||||
conn = HTTPConnection("example.com")
|
||||
conn.request("GET", path) # NOT OK -- user controlled fragment
|
||||
@@ -1,11 +0,0 @@
|
||||
from flask import request
|
||||
|
||||
import requests
|
||||
|
||||
def ssrf_test():
|
||||
user_input = request.args['untrusted_input']
|
||||
|
||||
requests.get(user_input) # NOT OK -- user has full control
|
||||
|
||||
# since `requests`` always uses complete URLs, it's not interesting to test more of
|
||||
# the framework directly. See `full_partial_test.py` for different ways to do SSRF.
|
||||
BIN
ql/Cargo.lock
generated
BIN
ql/Cargo.lock
generated
Binary file not shown.
@@ -1,6 +1,5 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"autobuilder",
|
||||
"extractor",
|
||||
"generator",
|
||||
"node-types",
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "ql-autobuilder"
|
||||
version = "0.1.0"
|
||||
authors = ["GitHub"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -1,43 +0,0 @@
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let dist = env::var("CODEQL_DIST").expect("CODEQL_DIST not set");
|
||||
let db = env::var("CODEQL_EXTRACTOR_QL_WIP_DATABASE")
|
||||
.expect("CODEQL_EXTRACTOR_QL_WIP_DATABASE not set");
|
||||
let codeql = if env::consts::OS == "windows" {
|
||||
"codeql.exe"
|
||||
} else {
|
||||
"codeql"
|
||||
};
|
||||
let codeql: PathBuf = [&dist, codeql].iter().collect();
|
||||
let mut cmd = Command::new(codeql);
|
||||
cmd.arg("database")
|
||||
.arg("index-files")
|
||||
.arg("--size-limit=5m")
|
||||
.arg("--language=ql")
|
||||
.arg("--working-dir=.")
|
||||
.arg(db);
|
||||
|
||||
let mut has_include_dir = false; // TODO: This is a horrible hack, wait for the post-merge discussion in https://github.com/github/codeql/pull/7444 to be resolved
|
||||
for line in env::var("LGTM_INDEX_FILTERS")
|
||||
.unwrap_or_default()
|
||||
.split('\n')
|
||||
{
|
||||
if let Some(stripped) = line.strip_prefix("include:") {
|
||||
cmd.arg("--include").arg(stripped);
|
||||
has_include_dir = true;
|
||||
} else if let Some(stripped) = line.strip_prefix("exclude:") {
|
||||
cmd.arg("--exclude").arg(stripped);
|
||||
}
|
||||
}
|
||||
if !has_include_dir {
|
||||
cmd.arg("--include-extension=.ql")
|
||||
.arg("--include-extension=.qll")
|
||||
.arg("--include-extension=.dbscheme")
|
||||
.arg("--include=**/qlpack.yml");
|
||||
}
|
||||
let exit = &cmd.spawn()?.wait()?;
|
||||
std::process::exit(exit.code().unwrap_or(1))
|
||||
}
|
||||
@@ -11,4 +11,3 @@ cp codeql-extractor.yml, ql\src\ql.dbscheme, ql\src\ql.dbscheme.stats extractor-
|
||||
cp -Recurse tools extractor-pack
|
||||
mkdir extractor-pack\tools\win64 | Out-Null
|
||||
cp target\release\ql-extractor.exe extractor-pack\tools\win64\extractor.exe
|
||||
cp target\release\ql-autobuilder.exe extractor-pack\tools\win64\autobuilder.exe
|
||||
|
||||
@@ -20,4 +20,3 @@ mkdir -p extractor-pack
|
||||
cp -r codeql-extractor.yml tools ql/src/ql.dbscheme ql/src/ql.dbscheme.stats extractor-pack/
|
||||
mkdir -p extractor-pack/tools/${platform}
|
||||
cp target/release/ql-extractor extractor-pack/tools/${platform}/extractor
|
||||
cp target/release/ql-autobuilder extractor-pack/tools/${platform}/autobuilder
|
||||
|
||||
@@ -13,7 +13,7 @@ tree-sitter = "0.19"
|
||||
tree-sitter-ql = { git = "https://github.com/tausbn/tree-sitter-ql.git", rev = "36bdc0eae196f9833182ce3f8932be63534121b3" }
|
||||
clap = "2.33"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
|
||||
tracing-subscriber = { version = "0.2", features = ["env-filter"] }
|
||||
rayon = "1.5.0"
|
||||
num_cpus = "1.13.0"
|
||||
regex = "1.4.3"
|
||||
|
||||
@@ -127,15 +127,6 @@ fn main() -> std::io::Result<()> {
|
||||
lines
|
||||
.par_iter()
|
||||
.try_for_each(|line| {
|
||||
// only consider files that end with .ql/.qll/.dbscheme/qlpack.yml
|
||||
// TODO: This is a bad fix, wait for the post-merge discussion in https://github.com/github/codeql/pull/7444 to be resolved
|
||||
if !line.ends_with(".ql")
|
||||
&& !line.ends_with(".qll")
|
||||
&& !line.ends_with(".dbscheme")
|
||||
&& !line.ends_with("qlpack.yml")
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
let path = PathBuf::from(line).canonicalize()?;
|
||||
let src_archive_file = path_for(&src_archive_dir, &path, "");
|
||||
let source = std::fs::read(&path)?;
|
||||
|
||||
@@ -10,5 +10,5 @@ edition = "2018"
|
||||
clap = "2.33"
|
||||
node-types = { path = "../node-types" }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
|
||||
tracing-subscriber = { version = "0.2", features = ["env-filter"] }
|
||||
tree-sitter-ql = { git = "https://github.com/tausbn/tree-sitter-ql.git", rev = "36bdc0eae196f9833182ce3f8932be63534121b3" }
|
||||
|
||||
@@ -8,4 +8,4 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_json = "1.0"
|
||||
@@ -58,9 +58,9 @@ class AstNode extends TAstNode {
|
||||
*/
|
||||
cached
|
||||
AstNode getAChild(string pred) {
|
||||
pred = directMember("getAnAnnotation") and result = this.getAnAnnotation()
|
||||
pred = directMember("getAnAnnotation") and result = getAnAnnotation()
|
||||
or
|
||||
pred = directMember("getQLDoc") and result = this.getQLDoc()
|
||||
pred = directMember("getQLDoc") and result = getQLDoc()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -606,7 +606,7 @@ class FieldDecl extends TFieldDecl, AstNode {
|
||||
/** Holds if this field is annotated as overriding another field. */
|
||||
predicate isOverride() { this.hasAnnotation("override") }
|
||||
|
||||
string getName() { result = this.getVarDecl().getName() }
|
||||
string getName() { result = getVarDecl().getName() }
|
||||
|
||||
override QLDoc getQLDoc() { result = any(Class c).getQLDocFor(this) }
|
||||
}
|
||||
@@ -673,7 +673,7 @@ class Module extends TModule, ModuleDeclaration {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Module" }
|
||||
|
||||
override string getName() { result = mod.getName().getChild().getValue() }
|
||||
override string getName() { result = mod.getName().(QL::ModuleName).getChild().getValue() }
|
||||
|
||||
/**
|
||||
* Gets a member of the module.
|
||||
@@ -699,7 +699,7 @@ class Module extends TModule, ModuleDeclaration {
|
||||
}
|
||||
|
||||
/**
|
||||
* A member of a module.
|
||||
* Something that can be member of a module.
|
||||
*/
|
||||
class ModuleMember extends TModuleMember, AstNode {
|
||||
/** Holds if this member is declared as `private`. */
|
||||
@@ -771,7 +771,7 @@ class Class extends TClass, TypeDeclaration, ModuleDeclaration {
|
||||
/**
|
||||
* Gets a field in this class.
|
||||
*/
|
||||
FieldDecl getAField() { result = this.getMember(_) }
|
||||
FieldDecl getAField() { result = getMember(_) }
|
||||
|
||||
/**
|
||||
* Gets a super-type referenced in the `extends` part of the class declaration.
|
||||
@@ -814,7 +814,7 @@ class Class extends TClass, TypeDeclaration, ModuleDeclaration {
|
||||
}
|
||||
|
||||
/** Holds if this class is abstract. */
|
||||
predicate isAbstract() { this.hasAnnotation("abstract") }
|
||||
predicate isAbstract() { hasAnnotation("abstract") }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -105,7 +105,7 @@ private predicate resolveQualifiedName(Import imp, ContainerOrModule m, int i) {
|
||||
(
|
||||
exists(Container c, Container parent |
|
||||
// should ideally look at `qlpack.yml` files
|
||||
parent = pragma[only_bind_out](imp.getLocation()).getFile().getParentContainer+() and
|
||||
parent = imp.getLocation().getFile().getParentContainer+() and
|
||||
exists(YAML::QLPack pack |
|
||||
pack.getFile().getParentContainer() = parent and
|
||||
c.getParentContainer() = pack.getADependency*().getFile().getParentContainer()
|
||||
@@ -122,8 +122,7 @@ private predicate resolveQualifiedName(Import imp, ContainerOrModule m, int i) {
|
||||
definesModule(container, q, m, _) and
|
||||
(
|
||||
exists(container.(Folder_).getFolder().getFile("qlpack.yml")) or
|
||||
container.(Folder_).getFolder() =
|
||||
pragma[only_bind_out](imp.getLocation()).getFile().getParentContainer() or
|
||||
container.(Folder_).getFolder() = imp.getLocation().getFile().getParentContainer() or
|
||||
not container instanceof Folder_
|
||||
)
|
||||
)
|
||||
@@ -195,7 +194,7 @@ private module Cached {
|
||||
not m = TFile(any(File f | f.getExtension() = "ql")) and
|
||||
not exists(me.getQualifier()) and
|
||||
exists(ContainerOrModule enclosing, string name | resolveModuleExprHelper(me, enclosing, name) |
|
||||
definesModule(enclosing, name, m, _)
|
||||
definesModule(enclosing.getEnclosing*(), name, m, _)
|
||||
)
|
||||
or
|
||||
exists(FileOrModule mid |
|
||||
@@ -206,7 +205,7 @@ private module Cached {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate resolveModuleExprHelper(ModuleExpr me, ContainerOrModule enclosing, string name) {
|
||||
enclosing = getEnclosingModule(me).getEnclosing*() and
|
||||
enclosing = getEnclosingModule(me) and
|
||||
name = me.getName()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ import codeql.IDEContextual
|
||||
*/
|
||||
external string selectedSourceFile();
|
||||
|
||||
// Overrides the configuration to print only nodes in the selected source file.
|
||||
/**
|
||||
* Overrides the configuration to print only nodes in the selected source file.
|
||||
*/
|
||||
class Cfg extends PrintAstConfiguration {
|
||||
override predicate shouldPrintNode(AstNode n) {
|
||||
super.shouldPrintNode(n) and
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@ where
|
||||
pred.getParent().getName() = className and
|
||||
pred.getName() = "getAPrimaryQlClass" and
|
||||
constant = pred.getBody().(ComparisonFormula).getRightOperand() and
|
||||
constant.getValue() = constantName and
|
||||
constant.(String).getValue() = constantName and
|
||||
// might be "Foo::classname", detect by matching with a regexp
|
||||
not constantName.regexpMatch(".*\\b" + className + "$") and
|
||||
// ignore constants with "?" in them
|
||||
|
||||
@@ -19,31 +19,12 @@ private predicate getAnOverridingParameter(
|
||||
parameter = pred.getParameter(index)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate getAnOverridingParameterWithDifferentNames(
|
||||
ClassPredicate pred, ClassPredicate sup, VarDecl parameter, int index
|
||||
) {
|
||||
from ClassPredicate pred, ClassPredicate sup, VarDecl parameter, int index
|
||||
where
|
||||
getAnOverridingParameter(pred, sup, parameter, index) and
|
||||
sup.getParameter(index).getName() != pred.getParameter(index).getName() and
|
||||
exists(int other | other != index |
|
||||
sup.getParameter(other).getName() = pred.getParameter(index).getName()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate getAnOverridingParameterWithDifferentNames2(
|
||||
ClassPredicate pred, ClassPredicate sup, VarDecl parameter, int index, string supName,
|
||||
string predName
|
||||
) {
|
||||
getAnOverridingParameterWithDifferentNames(pred, sup, parameter, index) and
|
||||
supName = pragma[only_bind_out](pragma[only_bind_out](sup).getParameter(index)).getName() and
|
||||
predName = pragma[only_bind_out](pragma[only_bind_out](pred).getParameter(index)).getName()
|
||||
}
|
||||
|
||||
from
|
||||
ClassPredicate pred, ClassPredicate sup, VarDecl parameter, int index, string supName,
|
||||
string predName
|
||||
where
|
||||
getAnOverridingParameterWithDifferentNames2(pred, sup, parameter, index, supName, predName) and
|
||||
supName != predName
|
||||
select parameter, predName + " was $@ in the super class.", sup.getParameter(index),
|
||||
"named " + supName
|
||||
select parameter, pred.getParameter(index).getName() + " was $@ in the super class.",
|
||||
sup.getParameter(index), "named " + sup.getParameter(index).getName()
|
||||
|
||||
@@ -14,7 +14,7 @@ predicate non_us_word(string wrong, string right) {
|
||||
exists(string s |
|
||||
wrong = s.splitAt("/", 0) and
|
||||
right = s.splitAt("/", 1) and
|
||||
s = ["colour/color", "authorise/authorize", "analyse/analyze", "behaviour/behavior"]
|
||||
s = ["colour/color", "authorise/authorize", "analyse/analyze"]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
@echo off
|
||||
|
||||
type NUL && "%CODEQL_EXTRACTOR_QL_ROOT%\tools\%CODEQL_PLATFORM%\autobuilder"
|
||||
type NUL && "%CODEQL_DIST%\codeql.exe" database index-files ^
|
||||
--include-extension=.ql ^
|
||||
--include-extension=.qll ^
|
||||
--include-extension=.dbscheme ^
|
||||
--include=**/qlpack.yml ^
|
||||
--size-limit=5m ^
|
||||
--language=ql ^
|
||||
"%CODEQL_EXTRACTOR_QL_WIP_DATABASE%"
|
||||
|
||||
exit /b %ERRORLEVEL%
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
exec "${CODEQL_EXTRACTOR_QL_ROOT}/tools/${CODEQL_PLATFORM}/autobuilder"
|
||||
set -eu
|
||||
|
||||
exec "${CODEQL_DIST}/codeql" database index-files \
|
||||
--include-extension=.ql \
|
||||
--include-extension=.qll \
|
||||
--include-extension=.dbscheme \
|
||||
--include=**/qlpack.yml \
|
||||
--size-limit=5m \
|
||||
--language=ql \
|
||||
--working-dir=.\
|
||||
"$CODEQL_EXTRACTOR_QL_WIP_DATABASE"
|
||||
|
||||
@@ -644,32 +644,3 @@ module Path {
|
||||
abstract class Range extends DataFlow::Node { }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that logs data.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `Logging::Range` instead.
|
||||
*/
|
||||
class Logging extends DataFlow::Node {
|
||||
Logging::Range range;
|
||||
|
||||
Logging() { this = range }
|
||||
|
||||
/** Gets an input that is logged. */
|
||||
DataFlow::Node getAnInput() { result = range.getAnInput() }
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new logging mechanisms. */
|
||||
module Logging {
|
||||
/**
|
||||
* A data-flow node that logs data.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `Logging` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets an input that is logged. */
|
||||
abstract DataFlow::Node getAnInput();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ private newtype TCompletion =
|
||||
TRetryCompletion() or
|
||||
TRaiseCompletion() or // TODO: Add exception type?
|
||||
TExitCompletion() or
|
||||
TNestedCompletion(TCompletion inner, TCompletion outer, int nestLevel) {
|
||||
TNestedCompletion(Completion inner, Completion outer, int nestLevel) {
|
||||
inner = TBreakCompletion() and
|
||||
outer instanceof NonNestedNormalCompletion and
|
||||
nestLevel = 0
|
||||
@@ -37,7 +37,7 @@ private newtype TCompletion =
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate nestedEnsureCompletion(TCompletion outer, int nestLevel) {
|
||||
private predicate nestedEnsureCompletion(Completion outer, int nestLevel) {
|
||||
(
|
||||
outer = TReturnCompletion()
|
||||
or
|
||||
|
||||
@@ -15,23 +15,11 @@ module Consistency {
|
||||
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||
string toString() { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
|
||||
predicate uniqueEnclosingCallableExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
|
||||
predicate uniqueNodeLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
|
||||
predicate missingLocationExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||
predicate postWithInFlowExclude(Node n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||
|
||||
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
|
||||
predicate reverseReadExclude(Node n) { none() }
|
||||
}
|
||||
|
||||
private class RelevantNode extends Node {
|
||||
@@ -58,7 +46,6 @@ module Consistency {
|
||||
n instanceof RelevantNode and
|
||||
c = count(nodeGetEnclosingCallable(n)) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
|
||||
msg = "Node should have one enclosing callable but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -79,7 +66,6 @@ module Consistency {
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
c != 1 and
|
||||
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
|
||||
msg = "Node should have one location but has " + c + "."
|
||||
)
|
||||
}
|
||||
@@ -90,8 +76,7 @@ module Consistency {
|
||||
strictcount(Node n |
|
||||
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
) and
|
||||
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
|
||||
)
|
||||
) and
|
||||
msg = "Nodes without location: " + c
|
||||
)
|
||||
@@ -187,7 +172,6 @@ module Consistency {
|
||||
|
||||
query predicate reverseRead(Node n, string msg) {
|
||||
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
||||
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@ private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.dataflow.FlowSummary
|
||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch
|
||||
private import codeql.ruby.CFG
|
||||
|
||||
/**
|
||||
* The `Kernel` module is included by the `Object` class, so its methods are available
|
||||
@@ -349,103 +347,3 @@ class RegexpEscapeSummary extends SummarizedCallable {
|
||||
preservesValue = false
|
||||
}
|
||||
}
|
||||
|
||||
/** A reference to a `Logger` instance */
|
||||
private DataFlow::Node loggerInstance() {
|
||||
result = API::getTopLevelMember("Logger").getAnInstantiation()
|
||||
or
|
||||
exists(DataFlow::Node inst |
|
||||
inst = loggerInstance() and
|
||||
inst.(DataFlow::LocalSourceNode).flowsTo(result)
|
||||
)
|
||||
or
|
||||
// Assume that a variable assigned as a `Logger` instance is always a
|
||||
// `Logger` instance. This covers class and instance variables where we can't
|
||||
// necessarily trace a dataflow path from assignment to use.
|
||||
exists(Variable v, Assignment a |
|
||||
a.getLeftOperand().getAVariable() = v and
|
||||
a.getRightOperand() = loggerInstance().asExpr().getExpr() and
|
||||
result.asExpr().getExpr().(VariableReadAccess).getVariable() = v
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a `Logger` instance method that causes a message to be logged.
|
||||
*/
|
||||
abstract class LoggerLoggingCall extends Logging::Range, DataFlow::CallNode {
|
||||
LoggerLoggingCall() { this.getReceiver() = loggerInstance() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Logger#add` or its alias `Logger#log`.
|
||||
*/
|
||||
private class LoggerAddCall extends LoggerLoggingCall {
|
||||
LoggerAddCall() { this.getMethodName() = ["add", "log"] }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
// Both the message and the progname are form part of the log output:
|
||||
// Logger#add(severity, message) / Logger#add(severity, message, progname)
|
||||
result = this.getArgument(1)
|
||||
or
|
||||
result = this.getArgument(2)
|
||||
or
|
||||
// a return value from the block in Logger#add(severity) <block> or in
|
||||
// Logger#add(severity, nil, progname) <block>
|
||||
(
|
||||
this.getNumberOfArguments() = 1
|
||||
or
|
||||
// TODO: this could track the value of the `message` argument to make
|
||||
// this check more accurate
|
||||
this.getArgument(1).asExpr().getExpr() instanceof NilLiteral
|
||||
) and
|
||||
exprNodeReturnedFrom(result, this.getBlock().asExpr().getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Logger#<<`.
|
||||
*/
|
||||
private class LoggerPushCall extends LoggerLoggingCall {
|
||||
LoggerPushCall() { this.getMethodName() = "<<" }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
// Logger#<<(msg)
|
||||
result = this.getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a `Logger` method that logs at a preset severity level.
|
||||
*
|
||||
* Specifically, these methods are `debug`, `error`, `fatal`, `info`,
|
||||
* `unknown`, and `warn`.
|
||||
*/
|
||||
private class LoggerInfoStyleCall extends LoggerLoggingCall {
|
||||
LoggerInfoStyleCall() {
|
||||
this.getMethodName() = ["debug", "error", "fatal", "info", "unknown", "warn"]
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
// `msg` from `Logger#info(msg)`,
|
||||
// or `progname` from `Logger#info(progname) <block>`
|
||||
result = this.getArgument(0)
|
||||
or
|
||||
// a return value from the block in `Logger#info(progname) <block>`
|
||||
exprNodeReturnedFrom(result, this.getBlock().asExpr().getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `Logger#progname=`. This sets a default progname.
|
||||
* This call does not log anything directly, but the assigned value can appear
|
||||
* in future log messages that do not specify a `progname` argument.
|
||||
*/
|
||||
private class LoggerSetPrognameCall extends LoggerLoggingCall {
|
||||
LoggerSetPrognameCall() { this.getMethodName() = "progname=" }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
exists(CfgNodes::ExprNodes::AssignExprCfgNode a | this.getArgument(0).asExpr() = a |
|
||||
result.asExpr() = a.getRhs()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user