mirror of
https://github.com/github/codeql.git
synced 2026-06-03 04:40:14 +02:00
Compare commits
1 Commits
esbena-tes
...
calumgrant
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b4935cd41 |
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
@@ -17,10 +17,3 @@ updates:
|
||||
ignore:
|
||||
- dependency-name: '*'
|
||||
update-types: ['version-update:semver-patch', 'version-update:semver-minor']
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "go/extractor"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "github/codeql-go"
|
||||
|
||||
4
.github/workflows/compile-queries.yml
vendored
4
.github/workflows/compile-queries.yml
vendored
@@ -29,9 +29,9 @@ jobs:
|
||||
# run with --check-only if running in a PR (github.sha != main)
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
- name: compile queries - full
|
||||
# do full compile if running on main - this populates the cache
|
||||
if : ${{ github.event_name != 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
|
||||
@@ -498,6 +498,22 @@
|
||||
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModelsExtensions.qll",
|
||||
"python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsExtensions.qll"
|
||||
],
|
||||
"TaintedFormatStringQuery Ruby/JS": [
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringQuery.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringQuery.qll"
|
||||
],
|
||||
"TaintedFormatStringCustomizations Ruby/JS": [
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringCustomizations.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringCustomizations.qll"
|
||||
],
|
||||
"HttpToFileAccessQuery JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessQuery.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessQuery.qll"
|
||||
],
|
||||
"HttpToFileAccessCustomizations JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
|
||||
],
|
||||
"Typo database": [
|
||||
"javascript/ql/src/Expressions/TypoDatabase.qll",
|
||||
"ql/ql/src/codeql_ql/style/TypoDatabase.qll"
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
## 0.10.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
|
||||
non-returning in the IR and dataflow.
|
||||
* Treat functions that reach the end of the function as returning in the IR.
|
||||
They used to be treated as unreachable but it is allowed in C.
|
||||
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.
|
||||
|
||||
## 0.9.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.
|
||||
5
cpp/ql/lib/change-notes/2023-09-07-return-from-end.md
Normal file
5
cpp/ql/lib/change-notes/2023-09-07-return-from-end.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Treat functions that reach the end of the function as returning in the IR.
|
||||
They used to be treated as unreachable but it is allowed in C.
|
||||
5
cpp/ql/lib/change-notes/2023-09-08-more-unreachble.md
Normal file
5
cpp/ql/lib/change-notes/2023-09-08-more-unreachble.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
|
||||
non-returning in the IR and dataflow.
|
||||
@@ -1,9 +0,0 @@
|
||||
## 0.10.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Functions that do not return due to calling functions that don't return (e.g. `exit`) are now detected as
|
||||
non-returning in the IR and dataflow.
|
||||
* Treat functions that reach the end of the function as returning in the IR.
|
||||
They used to be treated as unreachable but it is allowed in C.
|
||||
* The `DataFlow::asDefiningArgument` predicate now takes its argument from the range starting at `1` instead of `2`. Queries that depend on the single-parameter version of `DataFlow::asDefiningArgument` should have their arguments updated accordingly.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.10.0
|
||||
lastReleaseVersion: 0.9.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.10.1-dev
|
||||
version: 0.10.0-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -73,10 +73,6 @@ private int isSource(Expr bufferExpr, Element why) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Same as `getBufferSize`, but with the `why` column projected away to prevent large duplications. */
|
||||
pragma[nomagic]
|
||||
int getBufferSizeProj(Expr bufferExpr) { result = getBufferSize(bufferExpr, _) }
|
||||
|
||||
/**
|
||||
* Get the size in bytes of the buffer pointed to by an expression (if this can be determined).
|
||||
*/
|
||||
@@ -91,7 +87,7 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
||||
why = bufferVar and
|
||||
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
|
||||
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
||||
result = getBufferSizeProj(parentPtr) + bufferSize - parentClass.getSize()
|
||||
result = getBufferSize(parentPtr, _) + bufferSize - parentClass.getSize()
|
||||
|
|
||||
if exists(bufferVar.getType().getSize())
|
||||
then bufferSize = bufferVar.getType().getSize()
|
||||
@@ -99,6 +95,7 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
||||
)
|
||||
or
|
||||
// dataflow (all sources must be the same size)
|
||||
result = unique(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | getBufferSizeProj(def)) and
|
||||
result = unique(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | getBufferSize(def, _)) and
|
||||
// find reason
|
||||
exists(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | exists(getBufferSize(def, why)))
|
||||
}
|
||||
|
||||
@@ -555,7 +555,7 @@ predicate instructionForFullyConvertedCall(Instruction instr, CallInstruction ca
|
||||
}
|
||||
|
||||
/** Holds if `node` represents the output node for `call`. */
|
||||
predicate simpleOutNode(Node node, CallInstruction call) {
|
||||
private predicate simpleOutNode(Node node, CallInstruction call) {
|
||||
operandForFullyConvertedCall(node.asOperand(), call)
|
||||
or
|
||||
instructionForFullyConvertedCall(node.asInstruction(), call)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import SsaInternals as Ssa
|
||||
|
||||
/**
|
||||
@@ -36,7 +35,7 @@ DataFlow::Node callInput(CallInstruction call, FunctionInput input) {
|
||||
*/
|
||||
Node callOutput(CallInstruction call, FunctionOutput output) {
|
||||
// The return value
|
||||
simpleOutNode(result, call) and
|
||||
result.asInstruction() = call and
|
||||
output.isReturnValue()
|
||||
or
|
||||
// The side effect of a call on the value pointed to by an argument or qualifier
|
||||
@@ -83,7 +82,7 @@ Node callOutput(CallInstruction call, FunctionOutput output, int d) {
|
||||
// If there isn't an indirect out node for the call with indirection `d` then
|
||||
// we conflate this with the underlying `CallInstruction`.
|
||||
not exists(getIndirectReturnOutNode(call, d)) and
|
||||
n = result
|
||||
n.asInstruction() = result.asInstruction()
|
||||
or
|
||||
// The side effect of a call on the value pointed to by an argument or qualifier
|
||||
exists(Operand operand, int indirectionIndex |
|
||||
|
||||
@@ -1,16 +1,3 @@
|
||||
## 0.8.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
|
||||
in cases where a non-returning function is called.
|
||||
* The number of duplicated dataflow paths reported by queries has been significantly reduced.
|
||||
|
||||
## 0.7.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -82,20 +82,36 @@ module ValidState {
|
||||
* library will perform, and visit all the places where the size argument is modified.
|
||||
* 2. Once that dataflow traversal is done, we accumulate the offsets added at each places
|
||||
* where the offset is modified (see `validStateImpl`).
|
||||
*
|
||||
* Because we want to guarantee that each place where we modify the offset has a `PathNode`
|
||||
* we "flip" a boolean flow state in each `isAdditionalFlowStep`. This ensures that the node
|
||||
* has a corresponding `PathNode`.
|
||||
*/
|
||||
private module ValidStateConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { hasSize(_, source, _) }
|
||||
private module ValidStateConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState = boolean;
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSinkPairImpl(_, _, sink, _, _) }
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
hasSize(_, source, _) and
|
||||
state = false
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
isAdditionalFlowStep2(node1, node2, _)
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
isSinkPairImpl(_, _, sink, _, _) and
|
||||
state = [false, true]
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
isAdditionalFlowStep2(node1, node2, _) and
|
||||
state1 = [false, true] and
|
||||
state2 = state1.booleanNot()
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any() }
|
||||
}
|
||||
|
||||
private import DataFlow::Global<ValidStateConfig>
|
||||
private import DataFlow::GlobalWithState<ValidStateConfig>
|
||||
|
||||
private predicate inLoop(PathNode n) { n.getASuccessor+() = n }
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The number of duplicated dataflow paths reported by queries has been significantly reduced.
|
||||
5
cpp/ql/src/change-notes/2023-09-08-unreachble-edges.md
Normal file
5
cpp/ql/src/change-notes/2023-09-08-unreachble-edges.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
|
||||
in cases where a non-returning function is called.
|
||||
4
cpp/ql/src/change-notes/2023-10-03-double-free.md
Normal file
4
cpp/ql/src/change-notes/2023-10-03-double-free.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
4
cpp/ql/src/change-notes/2023-10-03-use-after-free.md
Normal file
4
cpp/ql/src/change-notes/2023-10-03-use-after-free.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: queryMetadata
|
||||
---
|
||||
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
@@ -1,12 +0,0 @@
|
||||
## 0.8.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The `cpp/double-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
* The `cpp/use-after-free` query has been further improved to reduce false positives and its precision has been increased from `medium` to `high`.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The queries `cpp/double-free` and `cpp/use-after-free` find fewer false positives
|
||||
in cases where a non-returning function is called.
|
||||
* The number of duplicated dataflow paths reported by queries has been significantly reduced.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.8.0
|
||||
lastReleaseVersion: 0.7.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.8.1-dev
|
||||
version: 0.8.0-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
failures
|
||||
astTypeBugs
|
||||
irTypeBugs
|
||||
failures
|
||||
|
||||
9
cpp/ql/test/library-tests/variables/this/this.cpp
Normal file
9
cpp/ql/test/library-tests/variables/this/this.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
class TestImplicitThis
|
||||
{
|
||||
public:
|
||||
int field;
|
||||
|
||||
int get() const {
|
||||
return field + this->field + get() + this->get();
|
||||
}
|
||||
};
|
||||
2
cpp/ql/test/library-tests/variables/this/this.expected
Normal file
2
cpp/ql/test/library-tests/variables/this/this.expected
Normal file
@@ -0,0 +1,2 @@
|
||||
| this.cpp:7:16:7:20 | this |
|
||||
| this.cpp:7:38:7:40 | this |
|
||||
5
cpp/ql/test/library-tests/variables/this/this.ql
Normal file
5
cpp/ql/test/library-tests/variables/this/this.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import cpp
|
||||
|
||||
from ThisExpr te
|
||||
where te.isCompilerGenerated()
|
||||
select te
|
||||
@@ -16,18 +16,18 @@ edges
|
||||
| test.cpp:91:9:91:16 | fread output argument | test.cpp:93:17:93:24 | filename indirection |
|
||||
| test.cpp:93:11:93:14 | strncat output argument | test.cpp:94:45:94:48 | path indirection |
|
||||
| test.cpp:93:17:93:24 | filename indirection | test.cpp:93:11:93:14 | strncat output argument |
|
||||
| test.cpp:106:20:106:38 | call to getenv | test.cpp:107:33:107:36 | path indirection |
|
||||
| test.cpp:106:20:106:25 | call to getenv | test.cpp:107:33:107:36 | path indirection |
|
||||
| test.cpp:106:20:106:38 | call to getenv indirection | test.cpp:107:33:107:36 | path indirection |
|
||||
| test.cpp:107:31:107:31 | call to operator+ | test.cpp:108:18:108:22 | call to c_str indirection |
|
||||
| test.cpp:107:33:107:36 | path indirection | test.cpp:107:31:107:31 | call to operator+ |
|
||||
| test.cpp:113:20:113:38 | call to getenv | test.cpp:114:19:114:22 | path indirection |
|
||||
| test.cpp:113:20:113:25 | call to getenv | test.cpp:114:19:114:22 | path indirection |
|
||||
| test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:19:114:22 | path indirection |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
|
||||
| test.cpp:114:17:114:17 | call to operator+ | test.cpp:114:10:114:23 | call to operator+ |
|
||||
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:10:114:23 | call to operator+ |
|
||||
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | call to operator+ |
|
||||
| test.cpp:119:20:119:38 | call to getenv | test.cpp:120:19:120:22 | path indirection |
|
||||
| test.cpp:119:20:119:25 | call to getenv | test.cpp:120:19:120:22 | path indirection |
|
||||
| test.cpp:119:20:119:38 | call to getenv indirection | test.cpp:120:19:120:22 | path indirection |
|
||||
| test.cpp:120:17:120:17 | call to operator+ | test.cpp:120:10:120:30 | call to data indirection |
|
||||
| test.cpp:120:19:120:22 | path indirection | test.cpp:120:17:120:17 | call to operator+ |
|
||||
@@ -91,12 +91,12 @@ nodes
|
||||
| test.cpp:93:11:93:14 | strncat output argument | semmle.label | strncat output argument |
|
||||
| test.cpp:93:17:93:24 | filename indirection | semmle.label | filename indirection |
|
||||
| test.cpp:94:45:94:48 | path indirection | semmle.label | path indirection |
|
||||
| test.cpp:106:20:106:38 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:106:20:106:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:106:20:106:38 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:107:31:107:31 | call to operator+ | semmle.label | call to operator+ |
|
||||
| test.cpp:107:33:107:36 | path indirection | semmle.label | path indirection |
|
||||
| test.cpp:108:18:108:22 | call to c_str indirection | semmle.label | call to c_str indirection |
|
||||
| test.cpp:113:20:113:38 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:113:20:113:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:113:20:113:38 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | semmle.label | call to operator+ |
|
||||
| test.cpp:114:10:114:23 | call to operator+ | semmle.label | call to operator+ |
|
||||
@@ -104,7 +104,7 @@ nodes
|
||||
| test.cpp:114:19:114:22 | path indirection | semmle.label | path indirection |
|
||||
| test.cpp:114:25:114:29 | call to c_str indirection | semmle.label | call to c_str indirection |
|
||||
| test.cpp:114:25:114:29 | call to c_str indirection | semmle.label | call to c_str indirection |
|
||||
| test.cpp:119:20:119:38 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:119:20:119:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:119:20:119:38 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:120:10:120:30 | call to data indirection | semmle.label | call to data indirection |
|
||||
| test.cpp:120:17:120:17 | call to operator+ | semmle.label | call to operator+ |
|
||||
@@ -158,13 +158,13 @@ subpaths
|
||||
| test.cpp:65:10:65:16 | command | test.cpp:62:9:62:16 | fread output argument | test.cpp:65:10:65:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:62:9:62:16 | fread output argument | user input (string read by fread) | test.cpp:64:11:64:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:85:32:85:38 | command | test.cpp:82:9:82:16 | fread output argument | test.cpp:85:32:85:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:82:9:82:16 | fread output argument | user input (string read by fread) | test.cpp:84:11:84:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:94:45:94:48 | path | test.cpp:91:9:91:16 | fread output argument | test.cpp:94:45:94:48 | path indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:91:9:91:16 | fread output argument | user input (string read by fread) | test.cpp:93:11:93:14 | strncat output argument | strncat output argument |
|
||||
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:38 | call to getenv | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:106:20:106:38 | call to getenv | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
|
||||
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:25 | call to getenv | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:106:20:106:25 | call to getenv | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
|
||||
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:38 | call to getenv indirection | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:106:20:106:38 | call to getenv indirection | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:25 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:25 | call to getenv | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:25 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:25 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv indirection | user input (an environment variable) | test.cpp:114:10:114:23 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:38 | call to getenv indirection | user input (an environment variable) | test.cpp:114:17:114:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:38 | call to getenv | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:119:20:119:38 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:25 | call to getenv | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:119:20:119:25 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:38 | call to getenv indirection | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:119:20:119:38 | call to getenv indirection | user input (an environment variable) | test.cpp:120:17:120:17 | call to operator+ | call to operator+ |
|
||||
| test.cpp:143:10:143:16 | command | test.cpp:140:9:140:11 | fread output argument | test.cpp:143:10:143:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:140:9:140:11 | fread output argument | user input (string read by fread) | test.cpp:142:11:142:17 | sprintf output argument | sprintf output argument |
|
||||
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:174:9:174:16 | fread output argument | user input (string read by fread) | test.cpp:177:13:177:17 | strncat output argument | strncat output argument |
|
||||
|
||||
@@ -5,33 +5,33 @@ edges
|
||||
| test.cpp:39:27:39:30 | argv indirection | test.cpp:49:32:49:35 | size |
|
||||
| test.cpp:39:27:39:30 | argv indirection | test.cpp:50:17:50:30 | size |
|
||||
| test.cpp:39:27:39:30 | argv indirection | test.cpp:53:35:53:60 | ... * ... |
|
||||
| test.cpp:124:18:124:31 | call to getenv | test.cpp:128:24:128:41 | ... * ... |
|
||||
| test.cpp:124:18:124:23 | call to getenv | test.cpp:128:24:128:41 | ... * ... |
|
||||
| test.cpp:124:18:124:31 | call to getenv indirection | test.cpp:128:24:128:41 | ... * ... |
|
||||
| test.cpp:133:19:133:32 | call to getenv | test.cpp:135:10:135:27 | ... * ... |
|
||||
| test.cpp:133:19:133:24 | call to getenv | test.cpp:135:10:135:27 | ... * ... |
|
||||
| test.cpp:133:19:133:32 | call to getenv indirection | test.cpp:135:10:135:27 | ... * ... |
|
||||
| test.cpp:148:20:148:33 | call to getenv | test.cpp:152:11:152:28 | ... * ... |
|
||||
| test.cpp:148:20:148:25 | call to getenv | test.cpp:152:11:152:28 | ... * ... |
|
||||
| test.cpp:148:20:148:33 | call to getenv indirection | test.cpp:152:11:152:28 | ... * ... |
|
||||
| test.cpp:209:8:209:23 | get_tainted_size indirection | test.cpp:241:9:241:24 | call to get_tainted_size |
|
||||
| test.cpp:211:14:211:27 | call to getenv | test.cpp:209:8:209:23 | get_tainted_size indirection |
|
||||
| test.cpp:211:14:211:19 | call to getenv | test.cpp:209:8:209:23 | get_tainted_size indirection |
|
||||
| test.cpp:211:14:211:27 | call to getenv indirection | test.cpp:209:8:209:23 | get_tainted_size indirection |
|
||||
| test.cpp:230:21:230:21 | s | test.cpp:231:21:231:21 | s |
|
||||
| test.cpp:237:24:237:37 | call to getenv | test.cpp:239:9:239:18 | local_size |
|
||||
| test.cpp:237:24:237:37 | call to getenv | test.cpp:245:11:245:20 | local_size |
|
||||
| test.cpp:237:24:237:37 | call to getenv | test.cpp:247:10:247:19 | local_size |
|
||||
| test.cpp:237:24:237:29 | call to getenv | test.cpp:239:9:239:18 | local_size |
|
||||
| test.cpp:237:24:237:29 | call to getenv | test.cpp:245:11:245:20 | local_size |
|
||||
| test.cpp:237:24:237:29 | call to getenv | test.cpp:247:10:247:19 | local_size |
|
||||
| test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:239:9:239:18 | local_size |
|
||||
| test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:245:11:245:20 | local_size |
|
||||
| test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:247:10:247:19 | local_size |
|
||||
| test.cpp:247:10:247:19 | local_size | test.cpp:230:21:230:21 | s |
|
||||
| test.cpp:250:20:250:27 | out_size | test.cpp:289:17:289:20 | get_size output argument |
|
||||
| test.cpp:250:20:250:27 | out_size | test.cpp:305:18:305:21 | get_size output argument |
|
||||
| test.cpp:251:18:251:31 | call to getenv | test.cpp:250:20:250:27 | out_size |
|
||||
| test.cpp:251:18:251:23 | call to getenv | test.cpp:250:20:250:27 | out_size |
|
||||
| test.cpp:251:18:251:31 | call to getenv indirection | test.cpp:250:20:250:27 | out_size |
|
||||
| test.cpp:259:20:259:33 | call to getenv | test.cpp:263:11:263:29 | ... * ... |
|
||||
| test.cpp:259:20:259:25 | call to getenv | test.cpp:263:11:263:29 | ... * ... |
|
||||
| test.cpp:259:20:259:33 | call to getenv indirection | test.cpp:263:11:263:29 | ... * ... |
|
||||
| test.cpp:289:17:289:20 | get_size output argument | test.cpp:291:11:291:28 | ... * ... |
|
||||
| test.cpp:305:18:305:21 | get_size output argument | test.cpp:308:10:308:27 | ... * ... |
|
||||
| test.cpp:353:18:353:31 | call to getenv | test.cpp:355:35:355:38 | size |
|
||||
| test.cpp:353:18:353:31 | call to getenv | test.cpp:356:35:356:38 | size |
|
||||
| test.cpp:353:18:353:23 | call to getenv | test.cpp:355:35:355:38 | size |
|
||||
| test.cpp:353:18:353:23 | call to getenv | test.cpp:356:35:356:38 | size |
|
||||
| test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:355:35:355:38 | size |
|
||||
| test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:356:35:356:38 | size |
|
||||
nodes
|
||||
@@ -42,37 +42,37 @@ nodes
|
||||
| test.cpp:49:32:49:35 | size | semmle.label | size |
|
||||
| test.cpp:50:17:50:30 | size | semmle.label | size |
|
||||
| test.cpp:53:35:53:60 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:124:18:124:31 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:124:18:124:23 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:124:18:124:31 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:128:24:128:41 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:133:19:133:32 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:133:19:133:24 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:133:19:133:32 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:135:10:135:27 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:148:20:148:33 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:148:20:148:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:148:20:148:33 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:152:11:152:28 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:209:8:209:23 | get_tainted_size indirection | semmle.label | get_tainted_size indirection |
|
||||
| test.cpp:211:14:211:27 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:211:14:211:19 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:211:14:211:27 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:230:21:230:21 | s | semmle.label | s |
|
||||
| test.cpp:231:21:231:21 | s | semmle.label | s |
|
||||
| test.cpp:237:24:237:37 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:237:24:237:29 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:237:24:237:37 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:239:9:239:18 | local_size | semmle.label | local_size |
|
||||
| test.cpp:241:9:241:24 | call to get_tainted_size | semmle.label | call to get_tainted_size |
|
||||
| test.cpp:245:11:245:20 | local_size | semmle.label | local_size |
|
||||
| test.cpp:247:10:247:19 | local_size | semmle.label | local_size |
|
||||
| test.cpp:250:20:250:27 | out_size | semmle.label | out_size |
|
||||
| test.cpp:251:18:251:31 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:251:18:251:23 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:251:18:251:31 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:259:20:259:33 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:259:20:259:25 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:259:20:259:33 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:263:11:263:29 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:289:17:289:20 | get_size output argument | semmle.label | get_size output argument |
|
||||
| test.cpp:291:11:291:28 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:305:18:305:21 | get_size output argument | semmle.label | get_size output argument |
|
||||
| test.cpp:308:10:308:27 | ... * ... | semmle.label | ... * ... |
|
||||
| test.cpp:353:18:353:31 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:353:18:353:23 | call to getenv | semmle.label | call to getenv |
|
||||
| test.cpp:353:18:353:31 | call to getenv indirection | semmle.label | call to getenv indirection |
|
||||
| test.cpp:355:35:355:38 | size | semmle.label | size |
|
||||
| test.cpp:356:35:356:38 | size | semmle.label | size |
|
||||
@@ -84,27 +84,27 @@ subpaths
|
||||
| test.cpp:49:25:49:30 | call to malloc | test.cpp:39:27:39:30 | argv indirection | test.cpp:49:32:49:35 | size | This allocation size is derived from $@ and might overflow. | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |
|
||||
| test.cpp:50:17:50:30 | new[] | test.cpp:39:27:39:30 | argv indirection | test.cpp:50:17:50:30 | size | This allocation size is derived from $@ and might overflow. | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |
|
||||
| test.cpp:53:21:53:27 | call to realloc | test.cpp:39:27:39:30 | argv indirection | test.cpp:53:35:53:60 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:39:27:39:30 | argv indirection | user input (a command-line argument) |
|
||||
| test.cpp:128:17:128:22 | call to malloc | test.cpp:124:18:124:31 | call to getenv | test.cpp:128:24:128:41 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:124:18:124:31 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:128:17:128:22 | call to malloc | test.cpp:124:18:124:23 | call to getenv | test.cpp:128:24:128:41 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:124:18:124:23 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:128:17:128:22 | call to malloc | test.cpp:124:18:124:31 | call to getenv indirection | test.cpp:128:24:128:41 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:124:18:124:31 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:135:3:135:8 | call to malloc | test.cpp:133:19:133:32 | call to getenv | test.cpp:135:10:135:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:133:19:133:32 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:135:3:135:8 | call to malloc | test.cpp:133:19:133:24 | call to getenv | test.cpp:135:10:135:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:133:19:133:24 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:135:3:135:8 | call to malloc | test.cpp:133:19:133:32 | call to getenv indirection | test.cpp:135:10:135:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:133:19:133:32 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:152:4:152:9 | call to malloc | test.cpp:148:20:148:33 | call to getenv | test.cpp:152:11:152:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:148:20:148:33 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:152:4:152:9 | call to malloc | test.cpp:148:20:148:25 | call to getenv | test.cpp:152:11:152:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:148:20:148:25 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:152:4:152:9 | call to malloc | test.cpp:148:20:148:33 | call to getenv indirection | test.cpp:152:11:152:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:148:20:148:33 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:231:14:231:19 | call to malloc | test.cpp:237:24:237:37 | call to getenv | test.cpp:231:21:231:21 | s | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:231:14:231:19 | call to malloc | test.cpp:237:24:237:29 | call to getenv | test.cpp:231:21:231:21 | s | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:29 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:231:14:231:19 | call to malloc | test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:231:21:231:21 | s | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:239:2:239:7 | call to malloc | test.cpp:237:24:237:37 | call to getenv | test.cpp:239:9:239:18 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:239:2:239:7 | call to malloc | test.cpp:237:24:237:29 | call to getenv | test.cpp:239:9:239:18 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:29 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:239:2:239:7 | call to malloc | test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:239:9:239:18 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:241:2:241:7 | call to malloc | test.cpp:211:14:211:27 | call to getenv | test.cpp:241:9:241:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow. | test.cpp:211:14:211:27 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:241:2:241:7 | call to malloc | test.cpp:211:14:211:19 | call to getenv | test.cpp:241:9:241:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow. | test.cpp:211:14:211:19 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:241:2:241:7 | call to malloc | test.cpp:211:14:211:27 | call to getenv indirection | test.cpp:241:9:241:24 | call to get_tainted_size | This allocation size is derived from $@ and might overflow. | test.cpp:211:14:211:27 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:245:2:245:9 | call to my_alloc | test.cpp:237:24:237:37 | call to getenv | test.cpp:245:11:245:20 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:245:2:245:9 | call to my_alloc | test.cpp:237:24:237:29 | call to getenv | test.cpp:245:11:245:20 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:29 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:245:2:245:9 | call to my_alloc | test.cpp:237:24:237:37 | call to getenv indirection | test.cpp:245:11:245:20 | local_size | This allocation size is derived from $@ and might overflow. | test.cpp:237:24:237:37 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:263:4:263:9 | call to malloc | test.cpp:259:20:259:33 | call to getenv | test.cpp:263:11:263:29 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:259:20:259:33 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:263:4:263:9 | call to malloc | test.cpp:259:20:259:25 | call to getenv | test.cpp:263:11:263:29 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:259:20:259:25 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:263:4:263:9 | call to malloc | test.cpp:259:20:259:33 | call to getenv indirection | test.cpp:263:11:263:29 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:259:20:259:33 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:291:4:291:9 | call to malloc | test.cpp:251:18:251:31 | call to getenv | test.cpp:291:11:291:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:291:4:291:9 | call to malloc | test.cpp:251:18:251:23 | call to getenv | test.cpp:291:11:291:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:23 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:291:4:291:9 | call to malloc | test.cpp:251:18:251:31 | call to getenv indirection | test.cpp:291:11:291:28 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:308:3:308:8 | call to malloc | test.cpp:251:18:251:31 | call to getenv | test.cpp:308:10:308:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:308:3:308:8 | call to malloc | test.cpp:251:18:251:23 | call to getenv | test.cpp:308:10:308:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:23 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:308:3:308:8 | call to malloc | test.cpp:251:18:251:31 | call to getenv indirection | test.cpp:308:10:308:27 | ... * ... | This allocation size is derived from $@ and might overflow. | test.cpp:251:18:251:31 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:355:25:355:33 | call to MyMalloc1 | test.cpp:353:18:353:31 | call to getenv | test.cpp:355:35:355:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:355:25:355:33 | call to MyMalloc1 | test.cpp:353:18:353:23 | call to getenv | test.cpp:355:35:355:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:23 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:355:25:355:33 | call to MyMalloc1 | test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:355:35:355:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv indirection | user input (an environment variable) |
|
||||
| test.cpp:356:25:356:33 | call to MyMalloc2 | test.cpp:353:18:353:31 | call to getenv | test.cpp:356:35:356:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:356:25:356:33 | call to MyMalloc2 | test.cpp:353:18:353:23 | call to getenv | test.cpp:356:35:356:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:23 | call to getenv | user input (an environment variable) |
|
||||
| test.cpp:356:25:356:33 | call to MyMalloc2 | test.cpp:353:18:353:31 | call to getenv indirection | test.cpp:356:35:356:38 | size | This allocation size is derived from $@ and might overflow. | test.cpp:353:18:353:31 | call to getenv indirection | user input (an environment variable) |
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Exclude @void_type from @value_type
|
||||
compatibility: full
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Add keyset to metadata_handle
|
||||
compatibility: full
|
||||
@@ -70,8 +70,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
foreach (var info in assemblyInfoByFileName.Values
|
||||
.OrderBy(info => info.Name)
|
||||
.ThenBy(info => info.NetCoreVersion ?? emptyVersion)
|
||||
.ThenBy(info => info.Version ?? emptyVersion)
|
||||
.ThenBy(info => info.Filename))
|
||||
.ThenBy(info => info.Version ?? emptyVersion))
|
||||
{
|
||||
foreach (var index in info.IndexStrings)
|
||||
{
|
||||
|
||||
@@ -322,11 +322,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
|
||||
var emptyVersion = new Version(0, 0);
|
||||
sortedReferences = sortedReferences
|
||||
.OrderBy(r => r.NetCoreVersion ?? emptyVersion)
|
||||
.ThenBy(r => r.Version ?? emptyVersion)
|
||||
.ThenBy(r => r.Filename)
|
||||
.ToList();
|
||||
sortedReferences = sortedReferences.OrderBy(r => r.NetCoreVersion ?? emptyVersion).ThenBy(r => r.Version ?? emptyVersion).ToList();
|
||||
|
||||
var finalAssemblyList = new Dictionary<string, AssemblyInfo>();
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// </summary>
|
||||
internal class NugetPackages
|
||||
{
|
||||
private readonly string? nugetExe;
|
||||
private readonly string nugetExe;
|
||||
private readonly ProgressMonitor progressMonitor;
|
||||
|
||||
/// <summary>
|
||||
@@ -36,18 +36,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
this.packageDirectory = packageDirectory;
|
||||
this.progressMonitor = progressMonitor;
|
||||
|
||||
nugetExe = ResolveNugetExe(sourceDir);
|
||||
packageFiles = new DirectoryInfo(sourceDir)
|
||||
.EnumerateFiles("packages.config", SearchOption.AllDirectories)
|
||||
.ToArray();
|
||||
|
||||
if (packageFiles.Length > 0)
|
||||
{
|
||||
nugetExe = ResolveNugetExe(sourceDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
progressMonitor.LogInfo("Found no packages.config file");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,7 +111,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
string exe, args;
|
||||
if (Util.Win32.IsWindows())
|
||||
{
|
||||
exe = nugetExe!;
|
||||
exe = nugetExe;
|
||||
args = string.Format("install -OutputDirectory {0} {1}", packageDirectory, package);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
## 1.7.0
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.6.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 1.7.0
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.0
|
||||
lastReleaseVersion: 1.6.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.1-dev
|
||||
version: 1.7.0-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
## 1.7.0
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.6.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 1.7.0
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.0
|
||||
lastReleaseVersion: 1.6.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.1-dev
|
||||
version: 1.7.0-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
| Program.cs:0:0:0:0 | Program.cs |
|
||||
| obj/Debug/net5.0/.NETCoreApp,Version=v5.0.AssemblyAttributes.cs:0:0:0:0 | obj/Debug/net5.0/.NETCoreApp,Version=v5.0.AssemblyAttributes.cs |
|
||||
| obj/Debug/net5.0/autobuild.AssemblyInfo.cs:0:0:0:0 | obj/Debug/net5.0/autobuild.AssemblyInfo.cs |
|
||||
@@ -1,5 +0,0 @@
|
||||
import csharp
|
||||
|
||||
from File f
|
||||
where f.fromSource()
|
||||
select f
|
||||
@@ -1 +0,0 @@
|
||||
var dummy = "dummy";
|
||||
@@ -1,14 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="DeleteBinObjFolders" BeforeTargets="Clean">
|
||||
<RemoveDir Directories=".\bin" />
|
||||
<RemoveDir Directories=".\obj" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "5.0.408"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
from create_database_utils import *
|
||||
|
||||
run_codeql_database_create([], lang="csharp", extra_args=["--extractor-option=cil=false"])
|
||||
@@ -1,7 +1,3 @@
|
||||
## 0.8.0
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.7.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.8.0
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.8.0
|
||||
lastReleaseVersion: 0.7.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 0.8.1-dev
|
||||
version: 0.8.0-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -397,7 +397,7 @@ class NonNestedType extends ValueOrRefType {
|
||||
/**
|
||||
* The `void` type.
|
||||
*/
|
||||
class VoidType extends ValueOrRefType, @void_type {
|
||||
class VoidType extends DotNet::ValueOrRefType, Type, @void_type {
|
||||
override predicate hasQualifiedName(string qualifier, string name) {
|
||||
qualifier = "System" and
|
||||
name = "Void"
|
||||
|
||||
@@ -456,7 +456,7 @@ case @type.kind of
|
||||
@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
|
||||
@floating_point_type = @float_type | @double_type;
|
||||
@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
|
||||
| @uint_ptr_type | @tuple_type | @void_type;
|
||||
| @uint_ptr_type | @tuple_type;
|
||||
@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
|
||||
| @dynamic_type;
|
||||
@value_or_ref_type = @value_type | @ref_type;
|
||||
@@ -1292,7 +1292,7 @@ expr_argument_name(
|
||||
lambda_expr_return_type(
|
||||
unique int id: @lambda_expr ref,
|
||||
int type_id: @type_or_ref ref);
|
||||
|
||||
|
||||
/** CONTROL/DATA FLOW **/
|
||||
|
||||
@control_flow_element = @stmt | @expr;
|
||||
@@ -2074,4 +2074,5 @@ cil_attribute_positional_argument(
|
||||
@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property |
|
||||
@callable | @value_or_ref_type | @void_type;
|
||||
|
||||
#keyset[entity, location]
|
||||
metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Remove keyset from metadata_handle
|
||||
compatibility: full
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
||||
description: Include @void_type in @value_type
|
||||
compatibility: full
|
||||
@@ -1,9 +1,3 @@
|
||||
## 0.8.0
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `cs/web/insecure-direct-object-reference`, to find instances of missing authorization checks for resources selected by an ID parameter.
|
||||
|
||||
## 0.7.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
## 0.8.0
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `cs/web/insecure-direct-object-reference`, to find instances of missing authorization checks for resources selected by an ID parameter.
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `cs/web/insecure-direct-object-reference`, to find instances of missing authorization checks for resources selected by an ID parameter.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.8.0
|
||||
lastReleaseVersion: 0.7.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 0.8.1-dev
|
||||
version: 0.8.0-dev
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -135,5 +135,5 @@ There are two methods for using CodeQL model packs with code scanning:
|
||||
For more information, see the following articles on the GitHub Docs site:
|
||||
|
||||
- Default setup of code scanning: `Extending CodeQL coverage with CodeQL model packs in default setup <https://docs.github.com/en/code-security/code-scanning/managing-your-code-scanning-configuration/editing-your-configuration-of-default-setup#extending-codeql-coverage-with-codeql-model-packs-in-default-setup>`__
|
||||
- Advanced setup of code scanning: `Extending CodeQL coverage with CodeQL model packs <https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-codeql-model-packs>`__
|
||||
- Advanced setup of code scanning: `Extending CodeQL coverage with CodeQL model packs <https://docs.github.com//en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-codeql-model-packs>`__
|
||||
- CodeQL CLI setup in external CI system: `Using model packs to analyze calls to custom dependencies <https://docs.github.com/en/code-security/code-scanning/using-codeql-code-scanning-with-your-existing-ci-system/configuring-codeql-cli-in-your-ci-system#using-model-packs-to-analyze-calls-to-custom-dependencies>`__
|
||||
|
||||
@@ -1993,10 +1993,6 @@ The following built-in predicates are members of type ``int``:
|
||||
+-------------------------+-------------+----------------+----------------------------------------------------------------------------------------------------------------+
|
||||
| ``toUnicode`` | string | | The result is the unicode character for the receiver seen as a unicode code point. |
|
||||
+-------------------------+-------------+----------------+----------------------------------------------------------------------------------------------------------------+
|
||||
| ``codePointAt`` | int | int | The result is the unicode code point at the index given by the argument. |
|
||||
+-------------------------+-------------+----------------+----------------------------------------------------------------------------------------------------------------+
|
||||
| ``codePointCount`` | int | int, int | The result is the number of unicode code points in the receiver between the given indices. |
|
||||
+-------------------------+-------------+----------------+----------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
The leftmost bit after ``bitShiftRightSigned`` depends on sign extension, whereas after ``bitShiftRight`` it is zero.
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ tools: $(addsuffix $(EXE),$(addprefix tools/bin/,$(BINARIES))) tools/tokenizer.j
|
||||
|
||||
.PHONY: $(addsuffix $(EXE),$(addprefix tools/bin/,$(BINARIES)))
|
||||
$(addsuffix $(EXE),$(addprefix tools/bin/,$(BINARIES))):
|
||||
go build -C extractor -mod=vendor -o ../$@ ./cli/$(basename $(@F))
|
||||
go build -mod=vendor -o $@ ./extractor/cli/$(basename $(@F))
|
||||
|
||||
tools-codeql: tools-$(CODEQL_PLATFORM)
|
||||
|
||||
@@ -61,19 +61,19 @@ tools-linux64: $(addprefix tools/linux64/,$(BINARIES))
|
||||
|
||||
.PHONY: $(addprefix tools/linux64/,$(BINARIES))
|
||||
$(addprefix tools/linux64/,$(BINARIES)):
|
||||
GOOS=linux GOARCH=amd64 go build -C extractor -mod=vendor -o ../$@ ./cli/$(@F)
|
||||
GOOS=linux GOARCH=amd64 go build -mod=vendor -o $@ ./extractor/cli/$(@F)
|
||||
|
||||
tools-osx64: $(addprefix tools/osx64/,$(BINARIES))
|
||||
|
||||
.PHONY: $(addprefix tools/osx64/,$(BINARIES))
|
||||
$(addprefix tools/osx64/,$(BINARIES)):
|
||||
GOOS=darwin GOARCH=amd64 go build -C extractor -mod=vendor -o ../$@ ./cli/$(@F)
|
||||
GOOS=darwin GOARCH=amd64 go build -mod=vendor -o $@ ./extractor/cli/$(@F)
|
||||
|
||||
tools-win64: $(addsuffix .exe,$(addprefix tools/win64/,$(BINARIES)))
|
||||
|
||||
.PHONY: $(addsuffix .exe,$(addprefix tools/win64/,$(BINARIES)))
|
||||
$(addsuffix .exe,$(addprefix tools/win64/,$(BINARIES))):
|
||||
env GOOS=windows GOARCH=amd64 go build -C extractor -mod=vendor -o ../$@ ./cli/$(basename $(@F))
|
||||
env GOOS=windows GOARCH=amd64 go build -mod=vendor -o $@ ./extractor/cli/$(basename $(@F))
|
||||
|
||||
.PHONY: extractor-common extractor extractor-full
|
||||
extractor-common: codeql-extractor.yml LICENSE ql/lib/go.dbscheme \
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
module github.com/github/codeql-go/extractor
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.13.0
|
||||
golang.org/x/tools v0.14.0
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.13.0 // indirect
|
||||
@@ -1,8 +0,0 @@
|
||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
10
go/go.mod
Normal file
10
go/go.mod
Normal file
@@ -0,0 +1,10 @@
|
||||
module github.com/github/codeql-go
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.12.0
|
||||
golang.org/x/tools v0.13.0
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.12.0 // indirect
|
||||
8
go/go.sum
Normal file
8
go/go.sum
Normal file
@@ -0,0 +1,8 @@
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
@@ -1,9 +1,3 @@
|
||||
## 0.7.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added Numeric and Boolean types to SQL injection sanitzers.
|
||||
|
||||
## 0.6.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added Numeric and Boolean types to SQL injection sanitzers.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Support has been added for file system access sinks in the following libraries: [net/http](https://pkg.go.dev/net/http), [Afero](https://github.com/spf13/afero), [beego](https://pkg.go.dev/github.com/astaxie/beego), [Echo](https://pkg.go.dev/github.com/labstack/echo), [Fiber](https://github.com/kataras/iris), [Gin](https://pkg.go.dev/github.com/gin-gonic/gin), [Iris](https://github.com/kataras/iris).
|
||||
@@ -1,5 +0,0 @@
|
||||
## 0.7.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added Numeric and Boolean types to SQL injection sanitzers.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.0
|
||||
lastReleaseVersion: 0.6.5
|
||||
|
||||
@@ -30,7 +30,6 @@ import semmle.go.dataflow.GlobalValueNumbering
|
||||
import semmle.go.dataflow.SSA
|
||||
import semmle.go.dataflow.TaintTracking
|
||||
import semmle.go.dataflow.TaintTracking2
|
||||
import semmle.go.frameworks.Afero
|
||||
import semmle.go.frameworks.Beego
|
||||
import semmle.go.frameworks.BeegoOrm
|
||||
import semmle.go.frameworks.Chi
|
||||
@@ -39,13 +38,11 @@ import semmle.go.frameworks.Echo
|
||||
import semmle.go.frameworks.ElazarlGoproxy
|
||||
import semmle.go.frameworks.Email
|
||||
import semmle.go.frameworks.Encoding
|
||||
import semmle.go.frameworks.Fiber
|
||||
import semmle.go.frameworks.Gin
|
||||
import semmle.go.frameworks.Glog
|
||||
import semmle.go.frameworks.GoMicro
|
||||
import semmle.go.frameworks.GoRestfulHttp
|
||||
import semmle.go.frameworks.Gqlgen
|
||||
import semmle.go.frameworks.Iris
|
||||
import semmle.go.frameworks.K8sIoApimachineryPkgRuntime
|
||||
import semmle.go.frameworks.K8sIoApiCoreV1
|
||||
import semmle.go.frameworks.K8sIoClientGo
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-all
|
||||
version: 0.7.1-dev
|
||||
version: 0.7.0-dev
|
||||
groups: go
|
||||
dbscheme: go.dbscheme
|
||||
extractor: go
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/**
|
||||
* Provides classes for working with sinks and taint propagators
|
||||
* from the `github.com/spf13/afero` package.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
/**
|
||||
* Provide File system access sinks of [afero](https://github.com/spf13/afero) framework
|
||||
*/
|
||||
module Afero {
|
||||
/**
|
||||
* Gets all versions of `github.com/spf13/afero`
|
||||
*/
|
||||
string aferoPackage() { result = package("github.com/spf13/afero", "") }
|
||||
|
||||
/**
|
||||
* The File system access sinks of [afero](https://github.com/spf13/afero) framework methods
|
||||
*/
|
||||
class AferoSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
AferoSystemAccess() {
|
||||
exists(Method m |
|
||||
m.hasQualifiedName(aferoPackage(), "HttpFs",
|
||||
["Create", "Open", "OpenFile", "Remove", "RemoveAll"]) and
|
||||
this = m.getACall()
|
||||
or
|
||||
m.hasQualifiedName(aferoPackage(), "RegexpFs",
|
||||
["Create", "Open", "OpenFile", "Remove", "RemoveAll", "Mkdir", "MkdirAll"]) and
|
||||
this = m.getACall()
|
||||
or
|
||||
m.hasQualifiedName(aferoPackage(), "ReadOnlyFs",
|
||||
["Create", "Open", "OpenFile", "ReadDir", "ReadlinkIfPossible", "Mkdir", "MkdirAll"]) and
|
||||
this = m.getACall()
|
||||
or
|
||||
m.hasQualifiedName(aferoPackage(), "OsFs",
|
||||
[
|
||||
"Create", "Open", "OpenFile", "ReadlinkIfPossible", "Remove", "RemoveAll", "Mkdir",
|
||||
"MkdirAll"
|
||||
]) and
|
||||
this = m.getACall()
|
||||
or
|
||||
m.hasQualifiedName(aferoPackage(), "MemMapFs",
|
||||
["Create", "Open", "OpenFile", "Remove", "RemoveAll", "Mkdir", "MkdirAll"]) and
|
||||
this = m.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The File system access sinks of [afero](https://github.com/spf13/afero) framework utility functions
|
||||
*
|
||||
* Afero Type is basically is an wrapper around utility functions which make them like a method, look at [here](https://github.com/spf13/afero/blob/cf95922e71986c0116204b6eeb3b345a01ffd842/ioutil.go#L61)
|
||||
*
|
||||
* The Types that are not vulnerable: `afero.BasePathFs` and `afero.IOFS`
|
||||
*/
|
||||
class AferoUtilityFunctionSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
int pathArg;
|
||||
|
||||
AferoUtilityFunctionSystemAccess() {
|
||||
// utility functions
|
||||
exists(Function f |
|
||||
f.hasQualifiedName(aferoPackage(),
|
||||
["WriteReader", "SafeWriteReader", "WriteFile", "ReadFile", "ReadDir"]) and
|
||||
this = f.getACall() and
|
||||
pathArg = 1 and
|
||||
not aferoSanitizer(this.getArgument(0))
|
||||
)
|
||||
or
|
||||
exists(Method m |
|
||||
m.hasQualifiedName(aferoPackage(), "Afero",
|
||||
["WriteReader", "SafeWriteReader", "WriteFile", "ReadFile", "ReadDir"]) and
|
||||
this = m.getACall() and
|
||||
pathArg = 0 and
|
||||
not aferoSanitizer(this.getReceiver())
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the Afero utility function has a first argument of a safe type like `NewBasePathFs`.
|
||||
*
|
||||
* e.g.
|
||||
* ```
|
||||
* basePathFs := afero.NewBasePathFs(osFS, "tmp")
|
||||
* afero.ReadFile(basePathFs, filepath)
|
||||
* ```
|
||||
*/
|
||||
predicate aferoSanitizer(DataFlow::Node n) {
|
||||
exists(Function f |
|
||||
f.hasQualifiedName(aferoPackage(), ["NewBasePathFs", "NewIOFS"]) and
|
||||
TaintTracking::localTaint(f.getACall(), n)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a dataflow node from n1 to n2 when initializing the Afero instance
|
||||
*
|
||||
* A helper for `aferoSanitizer` for when the Afero instance is initialized with one of the safe FS types like IOFS
|
||||
*
|
||||
* e.g.`n2 := &afero.Afero{Fs: afero.NewBasePathFs(osFS, "./")}` n1 is `afero.NewBasePathFs(osFS, "./")`
|
||||
*/
|
||||
class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(StructLit st | st.getType().hasQualifiedName(aferoPackage(), "Afero") |
|
||||
n1.asExpr() = st.getAnElement().(KeyValueExpr).getAChildExpr() and
|
||||
n2.asExpr() = st
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,31 +278,21 @@ module Beego {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The File system access sinks
|
||||
*/
|
||||
private class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
int pathArg;
|
||||
|
||||
FsOperations() {
|
||||
this.getTarget().hasQualifiedName(packagePath(), "Walk") and pathArg = 1
|
||||
this.getTarget().hasQualifiedName(packagePath(), "Walk")
|
||||
or
|
||||
exists(Method m | this = m.getACall() |
|
||||
m.hasQualifiedName(packagePath(), "FileSystem", "Open") and pathArg = 0
|
||||
or
|
||||
m.hasQualifiedName(packagePath(), "Controller", "SaveToFile") and pathArg = 1
|
||||
or
|
||||
m.hasQualifiedName(contextPackagePath(), "BeegoOutput", "Download") and
|
||||
pathArg = 0
|
||||
or
|
||||
// SaveToFileWithBuffer only available in v2
|
||||
m.hasQualifiedName("github.com/beego/beego/v2/server/web", "Controller",
|
||||
"SaveToFileWithBuffer") and
|
||||
pathArg = 1
|
||||
m.hasQualifiedName(packagePath(), "FileSystem", "Open") or
|
||||
m.hasQualifiedName(packagePath(), "Controller", "SaveToFile")
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) }
|
||||
override DataFlow::Node getAPathArgument() {
|
||||
this.getTarget().getName() = ["Walk", "SaveToFile"] and result = this.getArgument(1)
|
||||
or
|
||||
this.getTarget().getName() = "Open" and result = this.getArgument(0)
|
||||
}
|
||||
}
|
||||
|
||||
private class RedirectMethods extends Http::Redirect::Range, DataFlow::CallNode {
|
||||
|
||||
@@ -98,18 +98,4 @@ private module Echo {
|
||||
|
||||
override Http::ResponseWriter getResponseWriter() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The File system access sinks
|
||||
*/
|
||||
class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
FsOperations() {
|
||||
exists(Method m |
|
||||
m.hasQualifiedName(packagePath(), "Context", ["Attachment", "File"]) and
|
||||
this = m.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Provides classes for working the `github.com/gofiber/fiber` package.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
private module Fiber {
|
||||
/** Gets the package name `github.com/gofiber/fiber`. */
|
||||
string packagePath() { result = package("github.com/gofiber/fiber", "") }
|
||||
|
||||
/** Gets the v2 module path `github.com/gofiber/fiber/v2` */
|
||||
string v2modulePath() { result = "github.com/gofiber/fiber/v2" }
|
||||
|
||||
/**
|
||||
* The File system access sinks
|
||||
*/
|
||||
class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
int pathArg;
|
||||
|
||||
FsOperations() {
|
||||
exists(Method m |
|
||||
(
|
||||
m.hasQualifiedName(packagePath(), "Ctx", ["SendFile", "Download"]) and
|
||||
pathArg = 0
|
||||
or
|
||||
m.hasQualifiedName(packagePath(), "Ctx", "SaveFile") and
|
||||
pathArg = 1
|
||||
or
|
||||
m.hasQualifiedName(v2modulePath(), "Ctx", "SaveFileToStorage") and
|
||||
pathArg = 1
|
||||
) and
|
||||
this = m.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) }
|
||||
}
|
||||
}
|
||||
@@ -53,26 +53,4 @@ private module Gin {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The File system access sinks
|
||||
*/
|
||||
class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
int pathArg;
|
||||
|
||||
FsOperations() {
|
||||
exists(Method m |
|
||||
(
|
||||
m.hasQualifiedName(packagePath(), "Context", ["File", "FileAttachment"]) and
|
||||
pathArg = 0
|
||||
or
|
||||
m.hasQualifiedName(packagePath(), "Context", "SaveUploadedFile") and
|
||||
pathArg = 1
|
||||
) and
|
||||
this = m.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Provides classes for working the `github.com/kataras/iris` package.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
private module Iris {
|
||||
/** Gets the v1 module path `github.com/kataras/iris`. */
|
||||
string v1modulePath() { result = "github.com/kataras/iris" }
|
||||
|
||||
/** Gets the v12 module path `github.com/kataras/iris/v12` */
|
||||
string v12modulePath() { result = "github.com/kataras/iris/v12" }
|
||||
|
||||
/** Gets the path for the context package of all versions of beego. */
|
||||
string contextPackagePath() {
|
||||
result = v12contextPackagePath()
|
||||
or
|
||||
result = v1contextPackagePath()
|
||||
}
|
||||
|
||||
/** Gets the path for the context package of beego v12. */
|
||||
string v12contextPackagePath() { result = v12modulePath() + "/context" }
|
||||
|
||||
/** Gets the path for the context package of beego v1. */
|
||||
string v1contextPackagePath() { result = v1modulePath() + "/server/web/context" }
|
||||
|
||||
/**
|
||||
* The File system access sinks
|
||||
*/
|
||||
class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
int pathArg;
|
||||
|
||||
FsOperations() {
|
||||
exists(Method m |
|
||||
(
|
||||
m.hasQualifiedName(contextPackagePath(), "Context",
|
||||
["SendFile", "ServeFile", "SendFileWithRate", "ServeFileWithRate", "UploadFormFiles"]) and
|
||||
pathArg = 0
|
||||
or
|
||||
m.hasQualifiedName(v12contextPackagePath(), "Context", "SaveFormFile") and
|
||||
pathArg = 1
|
||||
) and
|
||||
this = m.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(pathArg) }
|
||||
}
|
||||
}
|
||||
@@ -288,18 +288,4 @@ module NetHttp {
|
||||
|
||||
override predicate guardedBy(DataFlow::Node check) { check = handlerReg.getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* The File system access sinks
|
||||
*/
|
||||
class HttpServeFile extends FileSystemAccess::Range, DataFlow::CallNode {
|
||||
HttpServeFile() {
|
||||
exists(Function f |
|
||||
f.hasQualifiedName("net/http", "ServeFile") and
|
||||
this = f.getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = this.getArgument(2) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,13 +195,8 @@ private class MaxValueState extends TMaxValueState {
|
||||
*/
|
||||
int getBitSize() { this = TMkMaxValueState(result, _) }
|
||||
|
||||
private ArchitectureBitSize architectureBitSize() { this = TMkMaxValueState(_, result) }
|
||||
|
||||
/** Gets whether the architecture is 32 bit or 64 bit, if it is known. */
|
||||
int getArchitectureBitSize() { result = this.architectureBitSize().toInt() }
|
||||
|
||||
/** Holds if the architecture is not known. */
|
||||
predicate architectureBitSizeUnknown() { this.architectureBitSize().isUnknown() }
|
||||
/** Gets whether the architecture is 32 bit or 64 bit, or if it is unknown. */
|
||||
ArchitectureBitSize getArchitectureBitSize() { this = TMkMaxValueState(_, result) }
|
||||
|
||||
/**
|
||||
* Gets the bitsize we should use for a sink.
|
||||
@@ -210,16 +205,17 @@ private class MaxValueState extends TMaxValueState {
|
||||
* we should use 32 bits, because that will find results that only exist on
|
||||
* 32-bit architectures.
|
||||
*/
|
||||
int getSinkBitSize() {
|
||||
if this = TMkMaxValueState(_, TMk64Bit()) then result = 64 else result = 32
|
||||
bindingset[default]
|
||||
int getSinkBitSize(int default) {
|
||||
if this = TMkMaxValueState(_, TMk64Bit()) then result = 64 else result = default
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() {
|
||||
exists(string suffix |
|
||||
suffix = " (on " + this.getArchitectureBitSize() + "-bit architecture)"
|
||||
suffix = " (on " + this.getArchitectureBitSize().toInt() + "-bit architecture)"
|
||||
or
|
||||
this.architectureBitSizeUnknown() and suffix = ""
|
||||
this.getArchitectureBitSize().isUnknown() and suffix = ""
|
||||
|
|
||||
result = "MaxValueState(max value <= 2^(" + this.getBitSize() + ")-1" + suffix
|
||||
)
|
||||
@@ -340,7 +336,9 @@ class UpperBoundCheck extends BarrierFlowStateTransformer {
|
||||
}
|
||||
|
||||
override predicate barrierFor(MaxValueState flowstate) {
|
||||
g.isBoundFor(flowstate.getBitSize(), flowstate.getSinkBitSize())
|
||||
// Use a default value of 32 for `MaxValueState.getSinkBitSize` because
|
||||
// this will find results that only exist on 32-bit architectures.
|
||||
g.isBoundFor(flowstate.getBitSize(), flowstate.getSinkBitSize(32))
|
||||
}
|
||||
|
||||
override MaxValueState transform(MaxValueState state) {
|
||||
@@ -349,13 +347,11 @@ class UpperBoundCheck extends BarrierFlowStateTransformer {
|
||||
max(int bitsize |
|
||||
bitsize = validBitSize() and
|
||||
bitsize < state.getBitSize() and
|
||||
not g.isBoundFor(bitsize, state.getSinkBitSize())
|
||||
// Use a default value of 32 for `MaxValueState.getSinkBitSize` because
|
||||
// this will find results that only exist on 32-bit architectures.
|
||||
not g.isBoundFor(bitsize, state.getSinkBitSize(32))
|
||||
) and
|
||||
(
|
||||
result.getArchitectureBitSize() = state.getArchitectureBitSize()
|
||||
or
|
||||
state.architectureBitSizeUnknown() and result.architectureBitSizeUnknown()
|
||||
)
|
||||
result.getArchitectureBitSize() = state.getArchitectureBitSize()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,10 +395,10 @@ private module ConversionWithoutBoundsCheckConfig implements DataFlow::StateConf
|
||||
then
|
||||
exists(int b | b = [32, 64] |
|
||||
state.getBitSize() = adjustBitSize(0, sourceIsSigned, b) and
|
||||
state.getArchitectureBitSize() = b
|
||||
state.getArchitectureBitSize().toInt() = b
|
||||
)
|
||||
else (
|
||||
state.architectureBitSizeUnknown() and
|
||||
state.getArchitectureBitSize().isUnknown() and
|
||||
state.getBitSize() =
|
||||
min(int bitsize |
|
||||
bitsize = validBitSize() and
|
||||
@@ -423,8 +419,10 @@ private module ConversionWithoutBoundsCheckConfig implements DataFlow::StateConf
|
||||
additional predicate isSink2(DataFlow::TypeCastNode sink, FlowState state) {
|
||||
sink.asExpr() instanceof ConversionExpr and
|
||||
exists(int architectureBitSize, IntegerType integerType, int sinkBitsize, boolean sinkIsSigned |
|
||||
architectureBitSize = getIntTypeBitSize(sink.getFile(), state.getSinkBitSize()) and
|
||||
not (state.getArchitectureBitSize() = 32 and architectureBitSize = 64) and
|
||||
// Use a default value of 32 for `MaxValueState.getSinkBitSize` because
|
||||
// this will find results that only exist on 32-bit architectures.
|
||||
architectureBitSize = getIntTypeBitSize(sink.getFile(), state.getSinkBitSize(32)) and
|
||||
not (state.getArchitectureBitSize().toInt() = 32 and architectureBitSize = 64) and
|
||||
sink.getResultType().getUnderlyingType() = integerType and
|
||||
(
|
||||
sinkBitsize = integerType.getSize()
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
## 0.7.0
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
## 0.7.0
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.0
|
||||
lastReleaseVersion: 0.6.5
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
)
|
||||
|
||||
var JwtKey = []byte("AllYourBase")
|
||||
|
||||
func main() {
|
||||
// BAD: usage of a harcoded Key
|
||||
verifyJWT(JWTFromUser)
|
||||
}
|
||||
|
||||
func LoadJwtKey(token *jwt.Token) (interface{}, error) {
|
||||
return JwtKey, nil
|
||||
}
|
||||
func verifyJWT(signedToken string) {
|
||||
fmt.Println("verifying JWT")
|
||||
DecodedToken, err := jwt.ParseWithClaims(signedToken, &CustomerInfo{}, LoadJwtKey)
|
||||
if claims, ok := DecodedToken.Claims.(*CustomerInfo); ok && DecodedToken.Valid {
|
||||
fmt.Printf("NAME:%v ,ID:%v\n", claims.Name, claims.ID)
|
||||
} else {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
A JSON Web Token (JWT) is used for authenticating and managing users in an application.
|
||||
</p>
|
||||
<p>
|
||||
Using a hard-coded secret key for parsing JWT tokens in open source projects
|
||||
can leave the application using the token vulnerable to authentication bypasses.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A JWT token is safe for enforcing authentication and access control as long as it can't be forged by a malicious actor. However, when a project exposes this secret publicly, these seemingly unforgeable tokens can now be easily forged.
|
||||
Since the authentication as well as access control is typically enforced through these JWT tokens, an attacker armed with the secret can create a valid authentication token for any user and may even gain access to other privileged parts of the application.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
Generating a cryptographically secure secret key during application initialization and using this generated key for future JWT parsing requests can prevent this vulnerability.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>
|
||||
The following code uses a hard-coded string as a secret for parsing user provided JWTs. In this case, an attacker can very easily forge a token by using the hard-coded secret.
|
||||
</p>
|
||||
|
||||
<sample src="ExampleBad.go" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
<li>
|
||||
CVE-2022-0664:
|
||||
<a href="https://nvd.nist.gov/vuln/detail/CVE-2022-0664">Use of Hard-coded Cryptographic Key in Go github.com/gravitl/netmaker prior to 0.8.5,0.9.4,0.10.0,0.10.1. </a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* @name Decoding JWT with hardcoded key
|
||||
* @description Decoding JWT Secret with a Constant value lead to authentication or authorization bypass
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @id go/parse-jwt-with-hardcoded-key
|
||||
* @tags security
|
||||
* experimental
|
||||
* external/cwe/cwe-321
|
||||
*/
|
||||
|
||||
import go
|
||||
import experimental.frameworks.JWT
|
||||
|
||||
module JwtParseWithConstantKeyConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof StringLit }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
// first part is the JWT Parsing Functions that get a func type as an argument
|
||||
// Find a node that has flow to a key Function argument
|
||||
// then find the first result node of this Function which is the secret key
|
||||
exists(FuncDef fd, DataFlow::Node n, DataFlow::ResultNode rn |
|
||||
fd = n.asExpr()
|
||||
or
|
||||
n = fd.(FuncDecl).getFunction().getARead()
|
||||
|
|
||||
GolangJwtKeyFunc::flow(n, _) and
|
||||
sink = rn and
|
||||
rn.getRoot() = fd and
|
||||
rn.getIndex() = 0
|
||||
)
|
||||
or
|
||||
// second part is the JWT Parsing Functions that get a string or byte as an argument
|
||||
sink = any(JwtParse jp).getKeyArg()
|
||||
}
|
||||
}
|
||||
|
||||
module GolangJwtKeyFuncConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Function f).getARead()
|
||||
or
|
||||
source.asExpr() = any(FuncDef fd)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(JwtParseWithKeyFunction parseJwt).getKeyFuncArg()
|
||||
}
|
||||
}
|
||||
|
||||
module JwtParseWithConstantKey = TaintTracking::Global<JwtParseWithConstantKeyConfig>;
|
||||
|
||||
module GolangJwtKeyFunc = TaintTracking::Global<GolangJwtKeyFuncConfig>;
|
||||
|
||||
import JwtParseWithConstantKey::PathGraph
|
||||
|
||||
from JwtParseWithConstantKey::PathNode source, JwtParseWithConstantKey::PathNode sink
|
||||
where JwtParseWithConstantKey::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This $@.", source.getNode(),
|
||||
"Constant Key is used as JWT Secret key"
|
||||
@@ -1,39 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// BAD: only decode jwt without verification
|
||||
notVerifyJWT(token)
|
||||
|
||||
// GOOD: decode with verification or verify plus decode
|
||||
notVerifyJWT(token)
|
||||
VerifyJWT(token)
|
||||
}
|
||||
|
||||
func notVerifyJWT(signedToken string) {
|
||||
fmt.Println("only decoding JWT")
|
||||
DecodedToken, _, err := jwt.NewParser().ParseUnverified(signedToken, &CustomerInfo{})
|
||||
if claims, ok := DecodedToken.Claims.(*CustomerInfo); ok {
|
||||
fmt.Printf("DecodedToken:%v\n", claims)
|
||||
} else {
|
||||
log.Fatal("error", err)
|
||||
}
|
||||
}
|
||||
func LoadJwtKey(token *jwt.Token) (interface{}, error) {
|
||||
return ARandomJwtKey, nil
|
||||
}
|
||||
func verifyJWT(signedToken string) {
|
||||
fmt.Println("verifying JWT")
|
||||
DecodedToken, err := jwt.ParseWithClaims(signedToken, &CustomerInfo{}, LoadJwtKey)
|
||||
if claims, ok := DecodedToken.Claims.(*CustomerInfo); ok && DecodedToken.Valid {
|
||||
fmt.Printf("NAME:%v ,ID:%v\n", claims.Name, claims.ID)
|
||||
} else {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
A JSON Web Token (JWT) is used for authenticating and managing users in an application.
|
||||
</p>
|
||||
<p>
|
||||
Only Decoding JWTs without checking if they have a valid signature or not can lead to security vulnerabilities.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
Don't use methods that only decode JWT, Instead use methods that verify the signature of JWT.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>
|
||||
In the following code you can see an Example from a popular Library.
|
||||
</p>
|
||||
|
||||
<sample src="Example.go" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://github.com/argoproj/argo-cd/security/advisories/GHSA-q9hr-j4rf-8fjc">JWT audience claim is not verified</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* @name Use of JWT Methods that only decode user provided Token
|
||||
* @description Using JWT methods without verification can cause to authorization or authentication bypass
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @id go/parse-jwt-without-verification
|
||||
* @tags security
|
||||
* experimental
|
||||
* external/cwe/cwe-321
|
||||
*/
|
||||
|
||||
import go
|
||||
import experimental.frameworks.JWT
|
||||
|
||||
module WithValidationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(JwtParse jwtParse).getTokenArg() or
|
||||
sink = any(JwtParseWithKeyFunction jwtParseWithKeyFunction).getTokenArg()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
golangJwtIsAdditionalFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
goJoseIsAdditionalFlowStep(nodeFrom, nodeTo)
|
||||
}
|
||||
}
|
||||
|
||||
module NoValidationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof UntrustedFlowSource and
|
||||
not WithValidation::flow(source, _)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(JwtUnverifiedParse parseUnverified).getTokenArg()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
golangJwtIsAdditionalFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
goJoseIsAdditionalFlowStep(nodeFrom, nodeTo)
|
||||
}
|
||||
}
|
||||
|
||||
module WithValidation = TaintTracking::Global<WithValidationConfig>;
|
||||
|
||||
module NoValidation = TaintTracking::Global<NoValidationConfig>;
|
||||
|
||||
import NoValidation::PathGraph
|
||||
|
||||
from NoValidation::PathNode source, NoValidation::PathNode sink
|
||||
where NoValidation::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
"This JWT is parsed without verification and received from $@.", source.getNode(),
|
||||
"this user-controlled source"
|
||||
@@ -1,265 +0,0 @@
|
||||
import go
|
||||
|
||||
/**
|
||||
* A abstract class which responsible for parsing a JWT token.
|
||||
*/
|
||||
abstract class JwtParseBase extends Function {
|
||||
/**
|
||||
* Gets argument number that responsible for JWT
|
||||
*
|
||||
* `-1` means the receiver is a argument node that responsible for JWT.
|
||||
* In this case, we must declare some additional taint steps.
|
||||
*/
|
||||
abstract int getTokenArgNum();
|
||||
|
||||
/**
|
||||
* Gets Argument as DataFlow node that responsible for JWT
|
||||
*/
|
||||
DataFlow::Node getTokenArg() {
|
||||
this.getTokenArgNum() != -1 and result = this.getACall().getArgument(this.getTokenArgNum())
|
||||
or
|
||||
this.getTokenArgNum() = -1 and result = this.getACall().getReceiver()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A abstract class which responsible for parsing a JWT token which the key parameter is a function type.
|
||||
*
|
||||
* Extends this class for Jwt parsing methods that accepts a function type as key.
|
||||
*/
|
||||
abstract class JwtParseWithKeyFunction extends JwtParseBase {
|
||||
/**
|
||||
* Gets argument number that responsible for a function returning the secret key
|
||||
*/
|
||||
abstract int getKeyFuncArgNum();
|
||||
|
||||
/**
|
||||
* Gets Argument as DataFlow node that responsible for a function returning the secret key
|
||||
*/
|
||||
DataFlow::Node getKeyFuncArg() { result = this.getACall().getArgument(this.getKeyFuncArgNum()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A abstract class which responsible for parsing a JWT token which the key parameter can be a string or byte type.
|
||||
*
|
||||
* Extends this class for Jwt parsing methods that accepts a non-function type as key.
|
||||
*/
|
||||
abstract class JwtParse extends JwtParseBase {
|
||||
/**
|
||||
* Gets argument number that responsible for secret key
|
||||
*/
|
||||
abstract int getKeyArgNum();
|
||||
|
||||
/**
|
||||
* Gets Argument as DataFlow node that responsible for secret key
|
||||
*/
|
||||
DataFlow::Node getKeyArg() { result = this.getACall().getArgument(this.getKeyArgNum()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A abstract class which responsible for parsing a JWT without verifying it
|
||||
*
|
||||
* Extends this class for Jwt parsing methods that don't verify JWT signature
|
||||
*/
|
||||
abstract class JwtUnverifiedParse extends JwtParseBase { }
|
||||
|
||||
/**
|
||||
* Gets `github.com/golang-jwt/jwt` and `github.com/dgrijalva/jwt-go`(previous name of `golang-jwt`) JWT packages
|
||||
*/
|
||||
string golangJwtPackage() {
|
||||
result = package(["github.com/golang-jwt/jwt", "github.com/dgrijalva/jwt-go"], "")
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that contains the following function and method:
|
||||
*
|
||||
* func (p *Parser) Parse(tokenString string, keyFunc Keyfunc)
|
||||
*
|
||||
* func Parse(tokenString string, keyFunc Keyfunc)
|
||||
*/
|
||||
class GolangJwtParse extends JwtParseWithKeyFunction {
|
||||
GolangJwtParse() {
|
||||
exists(Function f | f.hasQualifiedName(golangJwtPackage(), "Parse") | this = f)
|
||||
or
|
||||
exists(Method f | f.hasQualifiedName(golangJwtPackage(), "Parser", "Parse") | this = f)
|
||||
}
|
||||
|
||||
override int getKeyFuncArgNum() { result = 1 }
|
||||
|
||||
override int getTokenArgNum() { result = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that contains the following function and method:
|
||||
*
|
||||
* func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc)
|
||||
*
|
||||
* func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc)
|
||||
*/
|
||||
class GolangJwtParseWithClaims extends JwtParseWithKeyFunction {
|
||||
GolangJwtParseWithClaims() {
|
||||
exists(Function f | f.hasQualifiedName(golangJwtPackage(), "ParseWithClaims") | this = f)
|
||||
or
|
||||
exists(Method f | f.hasQualifiedName(golangJwtPackage(), "Parser", "ParseWithClaims") |
|
||||
this = f
|
||||
)
|
||||
}
|
||||
|
||||
override int getKeyFuncArgNum() { result = 2 }
|
||||
|
||||
override int getTokenArgNum() { result = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that contains the following method:
|
||||
*
|
||||
* func (p *Parser) ParseUnverified(tokenString string, claims Claims)
|
||||
*/
|
||||
class GolangJwtParseUnverified extends JwtUnverifiedParse {
|
||||
GolangJwtParseUnverified() {
|
||||
exists(Method f | f.hasQualifiedName(golangJwtPackage(), "Parser", "ParseUnverified") |
|
||||
this = f
|
||||
)
|
||||
}
|
||||
|
||||
override int getTokenArgNum() { result = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets `github.com/golang-jwt/jwt` and `github.com/dgrijalva/jwt-go`(previous name of `golang-jwt`) JWT packages
|
||||
*/
|
||||
string golangJwtRequestPackage() {
|
||||
result = package(["github.com/golang-jwt/jwt", "github.com/dgrijalva/jwt-go"], "request")
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that contains the following function:
|
||||
*
|
||||
* func ParseFromRequest(req *http.Request, extractor Extractor, keyFunc jwt.Keyfunc, options ...ParseFromRequestOption)
|
||||
*/
|
||||
class GolangJwtParseFromRequest extends JwtParseWithKeyFunction {
|
||||
GolangJwtParseFromRequest() {
|
||||
exists(Function f | f.hasQualifiedName(golangJwtRequestPackage(), "ParseFromRequest") |
|
||||
this = f
|
||||
)
|
||||
}
|
||||
|
||||
override int getKeyFuncArgNum() { result = 2 }
|
||||
|
||||
override int getTokenArgNum() { result = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that contains the following function:
|
||||
*
|
||||
* func ParseFromRequestWithClaims(req *http.Request, extractor Extractor, claims jwt.Claims, keyFunc jwt.Keyfunc)
|
||||
*/
|
||||
class GolangJwtParseFromRequestWithClaims extends JwtParseWithKeyFunction {
|
||||
GolangJwtParseFromRequestWithClaims() {
|
||||
exists(Function f |
|
||||
f.hasQualifiedName(golangJwtRequestPackage(), "ParseFromRequestWithClaims")
|
||||
|
|
||||
this = f
|
||||
)
|
||||
}
|
||||
|
||||
override int getKeyFuncArgNum() { result = 3 }
|
||||
|
||||
override int getTokenArgNum() { result = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets `gopkg.in/square/go-jose` and `github.com/go-jose/go-jose` jwt package
|
||||
*/
|
||||
string goJoseJwtPackage() {
|
||||
result = package(["gopkg.in/square/go-jose", "github.com/go-jose/go-jose"], "jwt")
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that contains the following method:
|
||||
*
|
||||
* func (t *JSONWebToken) Claims(key interface{}, dest ...interface{})
|
||||
*/
|
||||
class GoJoseParseWithClaims extends JwtParse {
|
||||
GoJoseParseWithClaims() {
|
||||
exists(Method f | f.hasQualifiedName(goJoseJwtPackage(), "JSONWebToken", "Claims") | this = f)
|
||||
}
|
||||
|
||||
override int getKeyArgNum() { result = 0 }
|
||||
|
||||
override int getTokenArgNum() { result = -1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that contains the following method:
|
||||
*
|
||||
* func (t *JSONWebToken) UnsafeClaimsWithoutVerification(dest ...interface{})
|
||||
*/
|
||||
class GoJoseUnsafeClaims extends JwtUnverifiedParse {
|
||||
GoJoseUnsafeClaims() {
|
||||
exists(Method f |
|
||||
f.hasQualifiedName(goJoseJwtPackage(), "JSONWebToken", "UnsafeClaimsWithoutVerification")
|
||||
|
|
||||
this = f
|
||||
)
|
||||
}
|
||||
|
||||
override int getTokenArgNum() { result = -1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for general additional steps related to parsing the secret keys in `golang-jwt/jwt`,`dgrijalva/jwt-go` packages
|
||||
*/
|
||||
predicate golangJwtIsAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
(
|
||||
f.hasQualifiedName(package("github.com/golang-jwt/jwt", ""),
|
||||
[
|
||||
"ParseECPrivateKeyFromPEM", "ParseECPublicKeyFromPEM", "ParseEdPrivateKeyFromPEM",
|
||||
"ParseEdPublicKeyFromPEM", "ParseRSAPrivateKeyFromPEM", "ParseRSAPublicKeyFromPEM",
|
||||
"RegisterSigningMethod"
|
||||
]) or
|
||||
f.hasQualifiedName(package("github.com/dgrijalva/jwt-go", ""),
|
||||
[
|
||||
"ParseECPrivateKeyFromPEM", "ParseECPublicKeyFromPEM", "ParseRSAPrivateKeyFromPEM",
|
||||
"ParseRSAPrivateKeyFromPEMWithPassword", "ParseRSAPublicKeyFromPEM"
|
||||
])
|
||||
) and
|
||||
call = f.getACall() and
|
||||
nodeFrom = call.getArgument(0) and
|
||||
nodeTo = call.getResult(0)
|
||||
or
|
||||
(
|
||||
f instanceof GolangJwtParse
|
||||
or
|
||||
f instanceof GolangJwtParseWithClaims
|
||||
) and
|
||||
call = f.getACall() and
|
||||
nodeFrom = call.getArgument(0) and
|
||||
nodeTo = call.getResult(0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for general additioanl steps related to parsing the secret keys in `go-jose` package
|
||||
*/
|
||||
predicate goJoseIsAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
exists(Function f, DataFlow::CallNode call |
|
||||
f.hasQualifiedName(goJoseJwtPackage(), ["ParseEncrypted", "ParseSigned"]) and
|
||||
call = f.getACall() and
|
||||
nodeFrom = call.getArgument(0) and
|
||||
nodeTo = call.getResult(0)
|
||||
)
|
||||
or
|
||||
exists(Method m, DataFlow::CallNode call |
|
||||
m.hasQualifiedName(goJoseJwtPackage(), "NestedJSONWebToken", "ParseSignedAndEncrypted") and
|
||||
call = m.getACall() and
|
||||
nodeFrom = call.getArgument(0) and
|
||||
nodeTo = call.getResult(0)
|
||||
or
|
||||
m.hasQualifiedName(goJoseJwtPackage(), "NestedJSONWebToken", "Decrypt") and
|
||||
call = m.getACall() and
|
||||
nodeFrom = call.getReceiver() and
|
||||
nodeTo = call.getResult(0)
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-queries
|
||||
version: 0.7.1-dev
|
||||
version: 0.7.0-dev
|
||||
groups:
|
||||
- go
|
||||
- queries
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user