mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
Merge branch 'github:main' into main
This commit is contained in:
@@ -33,6 +33,5 @@ codeql_pack(
|
||||
"//javascript/extractor:tools-extractor",
|
||||
"//javascript/resources",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
zips = {"//javascript/extractor/lib/typescript": "tools"},
|
||||
)
|
||||
|
||||
@@ -115,7 +115,7 @@ public class Identifiers {
|
||||
// rare.
|
||||
private static boolean isInAstralSet(int code, int[] set) {
|
||||
int pos = 0x10000;
|
||||
for (int i = 0; i < set.length; i += 2) {
|
||||
for (int i = 0; i < set.length - 1; i += 2) {
|
||||
pos += set[i];
|
||||
if (pos > code) return false;
|
||||
pos += set[i + 1];
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Enabled type-tracking to follow content through array methods
|
||||
* Improved modeling of `Array.prototype.splice` for when it is called with more than two arguments
|
||||
@@ -77,8 +77,12 @@ module ArrayTaintTracking {
|
||||
succ = call.getReceiver().getALocalSource() and
|
||||
call.getCalleeName() = ["push", "unshift"]
|
||||
or
|
||||
// `array.splice(i, del, e)`: if `e` is tainted, then so is `array`.
|
||||
pred = call.getArgument(2) and
|
||||
// `array.splice(i, del, e1, e2, ...)`: if any item is tainted, then so is `array`.
|
||||
pred = call.getArgument(any(int i | i >= 2)) and
|
||||
succ.(DataFlow::SourceNode).getAMethodCall("splice") = call
|
||||
or
|
||||
// `array.splice(i, del, ...e)`: if `e` is tainted, then so is `array`.
|
||||
pred = call.getASpreadArgument() and
|
||||
succ.(DataFlow::SourceNode).getAMethodCall("splice") = call
|
||||
or
|
||||
// `e = array.pop()`, `e = array.shift()`, or similar: if `array` is tainted, then so is `e`.
|
||||
@@ -115,9 +119,9 @@ private module ArrayDataFlow {
|
||||
* A step modeling the creation of an Array using the `Array.from(x)` method.
|
||||
* The step copies the elements of the argument (set, array, or iterator elements) into the resulting array.
|
||||
*/
|
||||
private class ArrayFrom extends DataFlow::SharedFlowStep {
|
||||
private class ArrayFrom extends PreCallGraphStep {
|
||||
override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
|
||||
DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp
|
||||
) {
|
||||
exists(DataFlow::CallNode call |
|
||||
call = arrayFromCall() and
|
||||
@@ -135,9 +139,9 @@ private module ArrayDataFlow {
|
||||
*
|
||||
* Such a step can occur both with the `push` and `unshift` methods, or when creating a new array.
|
||||
*/
|
||||
private class ArrayCopySpread extends DataFlow::SharedFlowStep {
|
||||
private class ArrayCopySpread extends PreCallGraphStep {
|
||||
override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
|
||||
DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp
|
||||
) {
|
||||
fromProp = arrayLikeElement() and
|
||||
toProp = arrayElement() and
|
||||
@@ -156,7 +160,7 @@ private module ArrayDataFlow {
|
||||
/**
|
||||
* A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`.
|
||||
*/
|
||||
private class ArrayAppendStep extends DataFlow::SharedFlowStep {
|
||||
private class ArrayAppendStep extends PreCallGraphStep {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
prop = arrayElement() and
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
@@ -187,7 +191,7 @@ private module ArrayDataFlow {
|
||||
* A step for reading/writing an element from an array inside a for-loop.
|
||||
* E.g. a read from `foo[i]` to `bar` in `for(var i = 0; i < arr.length; i++) {bar = foo[i]}`.
|
||||
*/
|
||||
private class ArrayIndexingStep extends DataFlow::SharedFlowStep {
|
||||
private class ArrayIndexingStep extends PreCallGraphStep {
|
||||
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
|
||||
exists(ArrayIndexingAccess access |
|
||||
prop = arrayElement() and
|
||||
@@ -209,7 +213,7 @@ private module ArrayDataFlow {
|
||||
* A step for retrieving an element from an array using `.pop()`, `.shift()`, or `.at()`.
|
||||
* E.g. `array.pop()`.
|
||||
*/
|
||||
private class ArrayPopStep extends DataFlow::SharedFlowStep {
|
||||
private class ArrayPopStep extends PreCallGraphStep {
|
||||
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call.getMethodName() = ["pop", "shift", "at"] and
|
||||
@@ -274,25 +278,38 @@ private module ArrayDataFlow {
|
||||
|
||||
/**
|
||||
* A step modeling that `splice` can insert elements into an array.
|
||||
* For example in `array.splice(i, del, e)`: if `e` is tainted, then so is `array
|
||||
* For example in `array.splice(i, del, e1, e2, ...)`: if any item is tainted, then so is `array`
|
||||
*/
|
||||
private class ArraySpliceStep extends DataFlow::SharedFlowStep {
|
||||
private class ArraySpliceStep extends PreCallGraphStep {
|
||||
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call.getMethodName() = "splice" and
|
||||
prop = arrayElement() and
|
||||
element = call.getArgument(2) and
|
||||
element = call.getArgument(any(int i | i >= 2)) and
|
||||
call = obj.getAMethodCall()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate loadStoreStep(
|
||||
DataFlow::Node pred, DataFlow::SourceNode succ, string fromProp, string toProp
|
||||
) {
|
||||
fromProp = arrayLikeElement() and
|
||||
toProp = arrayElement() and
|
||||
// `array.splice(i, del, ...arr)` variant
|
||||
exists(DataFlow::MethodCallNode mcn |
|
||||
mcn.getMethodName() = "splice" and
|
||||
pred = mcn.getASpreadArgument() and
|
||||
succ = mcn.getReceiver().getALocalSource()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step for modeling `concat`.
|
||||
* For example in `e = arr1.concat(arr2, arr3)`: if any of the `arr` is tainted, then so is `e`.
|
||||
*/
|
||||
private class ArrayConcatStep extends DataFlow::SharedFlowStep {
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
private class ArrayConcatStep extends PreCallGraphStep {
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call.getMethodName() = "concat" and
|
||||
prop = arrayElement() and
|
||||
@@ -305,8 +322,8 @@ private module ArrayDataFlow {
|
||||
/**
|
||||
* A step for modeling that elements from an array `arr` also appear in the result from calling `slice`/`splice`/`filter`.
|
||||
*/
|
||||
private class ArraySliceStep extends DataFlow::SharedFlowStep {
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
private class ArraySliceStep extends PreCallGraphStep {
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
exists(DataFlow::MethodCallNode call |
|
||||
call.getMethodName() = ["slice", "splice", "filter"] and
|
||||
prop = arrayElement() and
|
||||
@@ -319,7 +336,7 @@ private module ArrayDataFlow {
|
||||
/**
|
||||
* A step modeling that elements from an array `arr` are received by calling `find`.
|
||||
*/
|
||||
private class ArrayFindStep extends DataFlow::SharedFlowStep {
|
||||
private class ArrayFindStep extends PreCallGraphStep {
|
||||
override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
exists(DataFlow::CallNode call |
|
||||
call = arrayFindCall(pred) and
|
||||
@@ -382,7 +399,7 @@ private module ArrayLibraries {
|
||||
* E.g. `array-union` that creates a union of multiple arrays, or `array-uniq` that creates an array with unique elements.
|
||||
*/
|
||||
DataFlow::CallNode arrayCopyCall(DataFlow::Node array) {
|
||||
result = API::moduleImport(["array-union", "array-uniq", "uniq"]).getACall() and
|
||||
result = DataFlow::moduleImport(["array-union", "array-uniq", "uniq"]).getACall() and
|
||||
array = result.getAnArgument()
|
||||
}
|
||||
|
||||
@@ -401,8 +418,8 @@ private module ArrayLibraries {
|
||||
/**
|
||||
* A loadStoreStep for a library that copies the elements of an array into another array.
|
||||
*/
|
||||
private class ArrayCopyLoadStore extends DataFlow::SharedFlowStep {
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
private class ArrayCopyLoadStore extends PreCallGraphStep {
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
exists(DataFlow::CallNode call |
|
||||
call = arrayCopyCall(pred) and
|
||||
succ = call and
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Directly evaluating user input (for example, an HTTP request parameter) as code without properly
|
||||
sanitizing the input first allows an attacker arbitrary code execution. This can occur when user
|
||||
input is treated as JavaScript, or passed to a framework which interprets it as an expression to be
|
||||
evaluated. Examples include AngularJS expressions or JQuery selectors.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Avoid including user input in any expression which may be dynamically evaluated. If user input must
|
||||
be included, use context-specific escaping before
|
||||
including it. It is important that the correct escaping is used for the type of evaluation that will
|
||||
occur.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example shows part of the page URL being evaluated as JavaScript code on the server. This allows an
|
||||
attacker to provide JavaScript within the URL and send it to server. client side attacks need victim users interaction
|
||||
like clicking on a attacker provided URL.
|
||||
</p>
|
||||
|
||||
<sample src="examples/CodeInjection.js" />
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://www.owasp.org/index.php/Code_Injection">Code Injection</a>.
|
||||
</li>
|
||||
<li>
|
||||
Wikipedia: <a href="https://en.wikipedia.org/wiki/Code_injection">Code Injection</a>.
|
||||
</li>
|
||||
<li>
|
||||
PortSwigger Research Blog:
|
||||
<a href="https://portswigger.net/research/server-side-template-injection">Server-Side Template Injection</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,6 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="CodeInjection.inc.qhelp" />
|
||||
</qhelp>
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @name Code injection
|
||||
* @description Interpreting unsanitized user input as code allows a malicious user arbitrary
|
||||
* code execution.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.3
|
||||
* @precision high
|
||||
* @id js/code-injection-dynamic-import
|
||||
* @tags security
|
||||
* external/cwe/cwe-094
|
||||
* external/cwe/cwe-095
|
||||
* external/cwe/cwe-079
|
||||
* external/cwe/cwe-116
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import DataFlow
|
||||
import DataFlow::PathGraph
|
||||
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/** A non-first leaf in a string-concatenation. Seen as a sanitizer for dynamic import code injection. */
|
||||
class NonFirstStringConcatLeaf extends Sanitizer {
|
||||
NonFirstStringConcatLeaf() {
|
||||
exists(StringOps::ConcatenationRoot root |
|
||||
this = root.getALeaf() and
|
||||
not this = root.getFirstLeaf()
|
||||
)
|
||||
or
|
||||
exists(DataFlow::CallNode join |
|
||||
join = DataFlow::moduleMember("path", "join").getACall() and
|
||||
this = join.getArgument([1 .. join.getNumArgument() - 1])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The dynamic import expression input can be a `data:` URL which loads any module from that data
|
||||
*/
|
||||
class DynamicImport extends DataFlow::ExprNode {
|
||||
DynamicImport() { this = any(DynamicImportExpr e).getSource().flow() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The dynamic import expression input can be a `data:` URL which loads any module from that data
|
||||
*/
|
||||
class WorkerThreads extends DataFlow::Node {
|
||||
WorkerThreads() {
|
||||
this = API::moduleImport("node:worker_threads").getMember("Worker").getParameter(0).asSink()
|
||||
}
|
||||
}
|
||||
|
||||
class UrlConstructorLabel extends FlowLabel {
|
||||
UrlConstructorLabel() { this = "UrlConstructorLabel" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about code injection vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "CodeInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof DynamicImport }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, FlowLabel label) {
|
||||
sink instanceof WorkerThreads and label instanceof UrlConstructorLabel
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, FlowLabel predlbl, FlowLabel succlbl
|
||||
) {
|
||||
exists(DataFlow::NewNode newUrl | succ = newUrl |
|
||||
newUrl = DataFlow::globalVarRef("URL").getAnInstantiation() and
|
||||
pred = newUrl.getArgument(0)
|
||||
) and
|
||||
predlbl instanceof StandardFlowLabel and
|
||||
succlbl instanceof UrlConstructorLabel
|
||||
}
|
||||
}
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "This command line depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
@@ -0,0 +1,14 @@
|
||||
const { Worker } = require('node:worker_threads');
|
||||
var app = require('express')();
|
||||
|
||||
app.post('/path', async function (req, res) {
|
||||
const payload = req.query.queryParameter // like: payload = 'data:text/javascript,console.log("hello!");//'
|
||||
const payloadURL = new URL(payload)
|
||||
new Worker(payloadURL);
|
||||
});
|
||||
|
||||
app.post('/path2', async function (req, res) {
|
||||
const payload = req.query.queryParameter // like: payload = 'data:text/javascript,console.log("hello!");//'
|
||||
await import(payload)
|
||||
});
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
|
||||
<p>
|
||||
Controlling the value of arbitrary environment variables from user-controllable data is not safe.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
Restrict this operation only to privileged users or only for some not important environment variables.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
|
||||
<p>
|
||||
The following example allows unauthorized users to assign a value to any environment variable.
|
||||
</p>
|
||||
|
||||
<sample src="examples/Bad_Value_And_Key_Assignment.js" />
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li> <a href="https://huntr.com/bounties/00ec6847-125b-43e9-9658-d3cace1751d6/">Admin account TakeOver in mintplex-labs/anything-llm</a></li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @name User controlled arbitrary environment variable injection
|
||||
* @description creating arbitrary environment variables from user controlled data is not secure
|
||||
* @kind path-problem
|
||||
* @id js/env-key-and-value-injection
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision medium
|
||||
* @tags security
|
||||
* external/cwe/cwe-089
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/** A taint tracking configuration for unsafe environment injection. */
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "envInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = keyOfEnv() or
|
||||
sink = valueOfEnv()
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::InvokeNode ikn |
|
||||
ikn = DataFlow::globalVarRef("Object").getAMemberInvocation("keys")
|
||||
|
|
||||
pred = ikn.getArgument(0) and
|
||||
(
|
||||
succ = ikn.getAChainedMethodCall(["filter", "map"]) or
|
||||
succ = ikn or
|
||||
succ = ikn.getAChainedMethodCall("forEach").getABoundCallbackParameter(0, 0)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DataFlow::Node keyOfEnv() {
|
||||
result =
|
||||
NodeJSLib::process().getAPropertyRead("env").getAPropertyWrite().getPropertyNameExpr().flow()
|
||||
}
|
||||
|
||||
DataFlow::Node valueOfEnv() {
|
||||
result = API::moduleImport("process").getMember("env").getAMember().asSink()
|
||||
}
|
||||
|
||||
private predicate readToProcessEnv(DataFlow::Node envKey, DataFlow::Node envValue) {
|
||||
exists(DataFlow::PropWrite env |
|
||||
env = NodeJSLib::process().getAPropertyRead("env").getAPropertyWrite()
|
||||
|
|
||||
envKey = env.getPropertyNameExpr().flow() and
|
||||
envValue = env.getRhs()
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
Configuration cfgForValue, Configuration cfgForKey, DataFlow::PathNode source,
|
||||
DataFlow::PathNode envKey, DataFlow::PathNode envValue
|
||||
where
|
||||
cfgForValue.hasFlowPath(source, envKey) and
|
||||
envKey.getNode() = keyOfEnv() and
|
||||
cfgForKey.hasFlowPath(source, envValue) and
|
||||
envValue.getNode() = valueOfEnv() and
|
||||
readToProcessEnv(envKey.getNode(), envValue.getNode())
|
||||
select envKey.getNode(), source, envKey, "arbitrary environment variable assignment from this $@.",
|
||||
source.getNode(), "user controllable source"
|
||||
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
|
||||
<p>
|
||||
Assigning Value to environment variables from user-controllable data is not safe.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
Restrict this operation only to privileged users or only for some not important environment variables.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
|
||||
<p>
|
||||
The following example allows unauthorized users to assign a value to a critical environment variable.
|
||||
</p>
|
||||
|
||||
<sample src="examples/Bad_Value_Assignment.js" />
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li><a href="https://huntr.com/bounties/00ec6847-125b-43e9-9658-d3cace1751d6/">Admin account TakeOver in mintplex-labs/anything-llm</a></li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @name User controlled environment variable value injection
|
||||
* @description assigning important environment variables from user controlled data is not secure
|
||||
* @kind path-problem
|
||||
* @id js/env-value-injection
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision medium
|
||||
* @tags security
|
||||
* external/cwe/cwe-089
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/** A taint tracking configuration for unsafe environment injection. */
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "envInjection" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = API::moduleImport("process").getMember("env").getAMember().asSink()
|
||||
}
|
||||
}
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "this environment variable assignment is $@.",
|
||||
source.getNode(), "user controllable"
|
||||
@@ -0,0 +1,8 @@
|
||||
const http = require('node:http');
|
||||
|
||||
http.createServer((req, res) => {
|
||||
const { EnvValue, EnvKey } = req.body;
|
||||
process.env[EnvKey] = EnvValue; // NOT OK
|
||||
|
||||
res.end('env has been injected!');
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
const http = require('node:http');
|
||||
|
||||
http.createServer((req, res) => {
|
||||
const { EnvValue } = req.body;
|
||||
process.env["A_Critical_Env"] = EnvValue; // NOT OK
|
||||
|
||||
res.end('env has been injected!');
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
const jwtJsonwebtoken = require('jsonwebtoken');
|
||||
const jwt_decode = require('jwt-decode');
|
||||
const jwt_simple = require('jwt-simple');
|
||||
const jose = require('jose')
|
||||
const port = 3000
|
||||
|
||||
function getSecret() {
|
||||
return "A Safe generated random key"
|
||||
}
|
||||
app.get('/jose', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// BAD: no signature verification
|
||||
jose.decodeJwt(UserToken)
|
||||
})
|
||||
|
||||
app.get('/jwtDecode', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// BAD: no signature verification
|
||||
jwt_decode(UserToken)
|
||||
})
|
||||
|
||||
app.get('/jwtSimple', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// jwt.decode(token, key, noVerify, algorithm)
|
||||
// BAD: no signature verification
|
||||
jwt_simple.decode(UserToken, getSecret(), true);
|
||||
})
|
||||
|
||||
app.get('/jwtJsonwebtoken', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// BAD: no signature verification
|
||||
jwtJsonwebtoken.decode(UserToken)
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Example app listening on port ${port}`)
|
||||
})
|
||||
@@ -0,0 +1,56 @@
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
const jwtJsonwebtoken = require('jsonwebtoken');
|
||||
const jwt_decode = require('jwt-decode');
|
||||
const jwt_simple = require('jwt-simple');
|
||||
const jose = require('jose')
|
||||
const port = 3000
|
||||
|
||||
function getSecret() {
|
||||
return "A Safe generated random key"
|
||||
}
|
||||
|
||||
app.get('/jose1', async (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// GOOD: with signature verification
|
||||
await jose.jwtVerify(UserToken, new TextEncoder().encode(getSecret()))
|
||||
})
|
||||
|
||||
app.get('/jose2', async (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// GOOD: first without signature verification then with signature verification for same UserToken
|
||||
jose.decodeJwt(UserToken)
|
||||
await jose.jwtVerify(UserToken, new TextEncoder().encode(getSecret()))
|
||||
})
|
||||
|
||||
app.get('/jwtSimple1', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// GOOD: first without signature verification then with signature verification for same UserToken
|
||||
jwt_simple.decode(UserToken, getSecret(), false);
|
||||
jwt_simple.decode(UserToken, getSecret());
|
||||
})
|
||||
|
||||
app.get('/jwtSimple2', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// GOOD: with signature verification
|
||||
jwt_simple.decode(UserToken, getSecret(), true);
|
||||
jwt_simple.decode(UserToken, getSecret());
|
||||
})
|
||||
|
||||
app.get('/jwtJsonwebtoken1', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// GOOD: with signature verification
|
||||
jwtJsonwebtoken.verify(UserToken, getSecret())
|
||||
})
|
||||
|
||||
app.get('/jwtJsonwebtoken2', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// GOOD: first without signature verification then with signature verification for same UserToken
|
||||
jwtJsonwebtoken.decode(UserToken)
|
||||
jwtJsonwebtoken.verify(UserToken, getSecret())
|
||||
})
|
||||
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Example app listening on port ${port}`)
|
||||
})
|
||||
54
javascript/ql/src/experimental/Security/CWE-347/JWT.qll
Normal file
54
javascript/ql/src/experimental/Security/CWE-347/JWT.qll
Normal file
@@ -0,0 +1,54 @@
|
||||
import javascript
|
||||
|
||||
DataFlow::Node unverifiedDecode() {
|
||||
result = API::moduleImport("jsonwebtoken").getMember("decode").getParameter(0).asSink()
|
||||
or
|
||||
exists(API::Node verify | verify = API::moduleImport("jsonwebtoken").getMember("verify") |
|
||||
verify
|
||||
.getParameter(2)
|
||||
.getMember("algorithms")
|
||||
.getUnknownMember()
|
||||
.asSink()
|
||||
.mayHaveStringValue("none") and
|
||||
result = verify.getParameter(0).asSink()
|
||||
)
|
||||
or
|
||||
// jwt-simple
|
||||
exists(API::Node n | n = API::moduleImport("jwt-simple").getMember("decode") |
|
||||
n.getParameter(2).asSink().asExpr() = any(BoolLiteral b | b.getBoolValue() = true) and
|
||||
result = n.getParameter(0).asSink()
|
||||
)
|
||||
or
|
||||
// jwt-decode
|
||||
result = API::moduleImport("jwt-decode").getParameter(0).asSink()
|
||||
or
|
||||
//jose
|
||||
result = API::moduleImport("jose").getMember("decodeJwt").getParameter(0).asSink()
|
||||
}
|
||||
|
||||
DataFlow::Node verifiedDecode() {
|
||||
exists(API::Node verify | verify = API::moduleImport("jsonwebtoken").getMember("verify") |
|
||||
(
|
||||
not verify
|
||||
.getParameter(2)
|
||||
.getMember("algorithms")
|
||||
.getUnknownMember()
|
||||
.asSink()
|
||||
.mayHaveStringValue("none") or
|
||||
not exists(verify.getParameter(2).getMember("algorithms"))
|
||||
) and
|
||||
result = verify.getParameter(0).asSink()
|
||||
)
|
||||
or
|
||||
// jwt-simple
|
||||
exists(API::Node n | n = API::moduleImport("jwt-simple").getMember("decode") |
|
||||
(
|
||||
n.getParameter(2).asSink().asExpr() = any(BoolLiteral b | b.getBoolValue() = false) or
|
||||
not exists(n.getParameter(2))
|
||||
) and
|
||||
result = n.getParameter(0).asSink()
|
||||
or
|
||||
//jose
|
||||
result = API::moduleImport("jose").getMember("jwtVerify").getParameter(0).asSink()
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<!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 the proper usage of the most popular JWT libraries.
|
||||
</p>
|
||||
<sample src="Examples/Good.js" />
|
||||
|
||||
<p>
|
||||
In the following code, you can see the improper usage of the most popular JWT libraries.
|
||||
</p>
|
||||
<sample src="Examples/Bad.js" />
|
||||
</example>
|
||||
<references>
|
||||
<li>
|
||||
<a href="https://www.ghostccamm.com/blog/multi_strapi_vulns/#cve-2023-22893-authentication-bypass-for-aws-cognito-login-provider-in-strapi-versions-456">JWT claim has not been verified</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @name JWT missing secret or public key verification
|
||||
* @description The application does not verify the JWT payload with a cryptographic secret or public key.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 8.0
|
||||
* @precision high
|
||||
* @id js/decode-jwt-without-verification
|
||||
* @tags security
|
||||
* external/cwe/cwe-347
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import DataFlow::PathGraph
|
||||
import JWT
|
||||
|
||||
class ConfigurationUnverifiedDecode extends TaintTracking::Configuration {
|
||||
ConfigurationUnverifiedDecode() { this = "jsonwebtoken without any signature verification" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink = unverifiedDecode() }
|
||||
}
|
||||
|
||||
class ConfigurationVerifiedDecode extends TaintTracking::Configuration {
|
||||
ConfigurationVerifiedDecode() { this = "jsonwebtoken with signature verification" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink = verifiedDecode() }
|
||||
}
|
||||
|
||||
from ConfigurationUnverifiedDecode cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
not exists(ConfigurationVerifiedDecode cfg2 |
|
||||
cfg2.hasFlowPath(any(DataFlow::PathNode p | p.getNode() = source.getNode()), _)
|
||||
)
|
||||
select source.getNode(), source, sink, "Decoding JWT $@.", sink.getNode(),
|
||||
"without signature verification"
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @name JWT missing secret or public key verification
|
||||
* @description The application does not verify the JWT payload with a cryptographic secret or public key.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 8.0
|
||||
* @precision high
|
||||
* @id js/decode-jwt-without-verification-local-source
|
||||
* @tags security
|
||||
* external/cwe/cwe-347
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import DataFlow::PathGraph
|
||||
import JWT
|
||||
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "jsonwebtoken without any signature verification" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = [unverifiedDecode(), verifiedDecode()].getALocalSource()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = unverifiedDecode()
|
||||
or
|
||||
sink = verifiedDecode()
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `source` flows to the first parameter of jsonwebtoken.verify */
|
||||
predicate isSafe(Configuration cfg, DataFlow::Node source) {
|
||||
exists(DataFlow::Node sink |
|
||||
cfg.hasFlow(source, sink) and
|
||||
sink = verifiedDecode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if:
|
||||
* - `source` does not flow to the first parameter of `jsonwebtoken.verify`, and
|
||||
* - `source` flows to the first parameter of `jsonwebtoken.decode`
|
||||
*/
|
||||
predicate isVulnerable(Configuration cfg, DataFlow::Node source, DataFlow::Node sink) {
|
||||
not isSafe(cfg, source) and // i.e., source does not flow to a verify call
|
||||
cfg.hasFlow(source, sink) and // but it does flow to something else
|
||||
sink = unverifiedDecode() // and that something else is a call to decode.
|
||||
}
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
isVulnerable(cfg, source.getNode(), sink.getNode())
|
||||
select source.getNode(), source, sink, "Decoding JWT $@.", sink.getNode(),
|
||||
"without signature verification"
|
||||
@@ -0,0 +1,51 @@
|
||||
nodes
|
||||
| test.js:5:11:5:44 | payload |
|
||||
| test.js:5:21:5:44 | req.que ... rameter |
|
||||
| test.js:5:21:5:44 | req.que ... rameter |
|
||||
| test.js:6:9:6:43 | payloadURL |
|
||||
| test.js:6:22:6:43 | new URL ... + sth) |
|
||||
| test.js:6:30:6:36 | payload |
|
||||
| test.js:6:30:6:42 | payload + sth |
|
||||
| test.js:7:16:7:25 | payloadURL |
|
||||
| test.js:7:16:7:25 | payloadURL |
|
||||
| test.js:9:5:9:39 | payloadURL |
|
||||
| test.js:9:18:9:39 | new URL ... + sth) |
|
||||
| test.js:9:26:9:32 | payload |
|
||||
| test.js:9:26:9:38 | payload + sth |
|
||||
| test.js:10:16:10:25 | payloadURL |
|
||||
| test.js:10:16:10:25 | payloadURL |
|
||||
| test.js:17:11:17:44 | payload |
|
||||
| test.js:17:21:17:44 | req.que ... rameter |
|
||||
| test.js:17:21:17:44 | req.que ... rameter |
|
||||
| test.js:18:18:18:24 | payload |
|
||||
| test.js:18:18:18:24 | payload |
|
||||
| test.js:19:18:19:24 | payload |
|
||||
| test.js:19:18:19:30 | payload + sth |
|
||||
| test.js:19:18:19:30 | payload + sth |
|
||||
edges
|
||||
| test.js:5:11:5:44 | payload | test.js:6:30:6:36 | payload |
|
||||
| test.js:5:11:5:44 | payload | test.js:9:26:9:32 | payload |
|
||||
| test.js:5:21:5:44 | req.que ... rameter | test.js:5:11:5:44 | payload |
|
||||
| test.js:5:21:5:44 | req.que ... rameter | test.js:5:11:5:44 | payload |
|
||||
| test.js:6:9:6:43 | payloadURL | test.js:7:16:7:25 | payloadURL |
|
||||
| test.js:6:9:6:43 | payloadURL | test.js:7:16:7:25 | payloadURL |
|
||||
| test.js:6:22:6:43 | new URL ... + sth) | test.js:6:9:6:43 | payloadURL |
|
||||
| test.js:6:30:6:36 | payload | test.js:6:30:6:42 | payload + sth |
|
||||
| test.js:6:30:6:42 | payload + sth | test.js:6:22:6:43 | new URL ... + sth) |
|
||||
| test.js:9:5:9:39 | payloadURL | test.js:10:16:10:25 | payloadURL |
|
||||
| test.js:9:5:9:39 | payloadURL | test.js:10:16:10:25 | payloadURL |
|
||||
| test.js:9:18:9:39 | new URL ... + sth) | test.js:9:5:9:39 | payloadURL |
|
||||
| test.js:9:26:9:32 | payload | test.js:9:26:9:38 | payload + sth |
|
||||
| test.js:9:26:9:38 | payload + sth | test.js:9:18:9:39 | new URL ... + sth) |
|
||||
| test.js:17:11:17:44 | payload | test.js:18:18:18:24 | payload |
|
||||
| test.js:17:11:17:44 | payload | test.js:18:18:18:24 | payload |
|
||||
| test.js:17:11:17:44 | payload | test.js:19:18:19:24 | payload |
|
||||
| test.js:17:21:17:44 | req.que ... rameter | test.js:17:11:17:44 | payload |
|
||||
| test.js:17:21:17:44 | req.que ... rameter | test.js:17:11:17:44 | payload |
|
||||
| test.js:19:18:19:24 | payload | test.js:19:18:19:30 | payload + sth |
|
||||
| test.js:19:18:19:24 | payload | test.js:19:18:19:30 | payload + sth |
|
||||
#select
|
||||
| test.js:7:16:7:25 | payloadURL | test.js:5:21:5:44 | req.que ... rameter | test.js:7:16:7:25 | payloadURL | This command line depends on a $@. | test.js:5:21:5:44 | req.que ... rameter | user-provided value |
|
||||
| test.js:10:16:10:25 | payloadURL | test.js:5:21:5:44 | req.que ... rameter | test.js:10:16:10:25 | payloadURL | This command line depends on a $@. | test.js:5:21:5:44 | req.que ... rameter | user-provided value |
|
||||
| test.js:18:18:18:24 | payload | test.js:17:21:17:44 | req.que ... rameter | test.js:18:18:18:24 | payload | This command line depends on a $@. | test.js:17:21:17:44 | req.que ... rameter | user-provided value |
|
||||
| test.js:19:18:19:30 | payload + sth | test.js:17:21:17:44 | req.que ... rameter | test.js:19:18:19:30 | payload + sth | This command line depends on a $@. | test.js:17:21:17:44 | req.que ... rameter | user-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE-094-dataURL/CodeInjection.ql
|
||||
@@ -0,0 +1,22 @@
|
||||
const { Worker } = require('node:worker_threads');
|
||||
var app = require('express')();
|
||||
|
||||
app.post('/path', async function (req, res) {
|
||||
const payload = req.query.queryParameter // like: payload = 'data:text/javascript,console.log("hello!");//'
|
||||
let payloadURL = new URL(payload + sth) // NOT OK
|
||||
new Worker(payloadURL);
|
||||
|
||||
payloadURL = new URL(payload + sth) // NOT OK
|
||||
new Worker(payloadURL);
|
||||
|
||||
payloadURL = new URL(sth + payload) // OK
|
||||
new Worker(payloadURL);
|
||||
});
|
||||
|
||||
app.post('/path2', async function (req, res) {
|
||||
const payload = req.query.queryParameter // like: payload = 'data:text/javascript,console.log("hello!");//'
|
||||
await import(payload) // NOT OK
|
||||
await import(payload + sth) // NOT OK
|
||||
await import(sth + payload) // OK
|
||||
});
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
nodes
|
||||
| test.js:5:9:5:28 | { EnvValue, EnvKey } |
|
||||
| test.js:5:9:5:39 | EnvKey |
|
||||
| test.js:5:9:5:39 | EnvValue |
|
||||
| test.js:5:11:5:18 | EnvValue |
|
||||
| test.js:5:21:5:26 | EnvKey |
|
||||
| test.js:5:32:5:39 | req.body |
|
||||
| test.js:5:32:5:39 | req.body |
|
||||
| test.js:6:15:6:20 | EnvKey |
|
||||
| test.js:6:15:6:20 | EnvKey |
|
||||
| test.js:6:25:6:32 | EnvValue |
|
||||
| test.js:6:25:6:32 | EnvValue |
|
||||
| test.js:7:15:7:20 | EnvKey |
|
||||
| test.js:7:15:7:20 | EnvKey |
|
||||
| test.js:7:25:7:32 | EnvValue |
|
||||
| test.js:7:25:7:32 | EnvValue |
|
||||
| test.js:13:9:13:28 | { EnvValue, EnvKey } |
|
||||
| test.js:13:9:13:39 | EnvKey |
|
||||
| test.js:13:9:13:39 | EnvValue |
|
||||
| test.js:13:11:13:18 | EnvValue |
|
||||
| test.js:13:21:13:26 | EnvKey |
|
||||
| test.js:13:32:13:39 | req.body |
|
||||
| test.js:13:32:13:39 | req.body |
|
||||
| test.js:15:15:15:20 | EnvKey |
|
||||
| test.js:15:15:15:20 | EnvKey |
|
||||
| test.js:16:26:16:33 | EnvValue |
|
||||
| test.js:16:26:16:33 | EnvValue |
|
||||
edges
|
||||
| test.js:5:9:5:28 | { EnvValue, EnvKey } | test.js:5:11:5:18 | EnvValue |
|
||||
| test.js:5:9:5:28 | { EnvValue, EnvKey } | test.js:5:21:5:26 | EnvKey |
|
||||
| test.js:5:9:5:39 | EnvKey | test.js:6:15:6:20 | EnvKey |
|
||||
| test.js:5:9:5:39 | EnvKey | test.js:6:15:6:20 | EnvKey |
|
||||
| test.js:5:9:5:39 | EnvKey | test.js:7:15:7:20 | EnvKey |
|
||||
| test.js:5:9:5:39 | EnvKey | test.js:7:15:7:20 | EnvKey |
|
||||
| test.js:5:9:5:39 | EnvValue | test.js:6:25:6:32 | EnvValue |
|
||||
| test.js:5:9:5:39 | EnvValue | test.js:6:25:6:32 | EnvValue |
|
||||
| test.js:5:9:5:39 | EnvValue | test.js:7:25:7:32 | EnvValue |
|
||||
| test.js:5:9:5:39 | EnvValue | test.js:7:25:7:32 | EnvValue |
|
||||
| test.js:5:11:5:18 | EnvValue | test.js:5:9:5:39 | EnvValue |
|
||||
| test.js:5:21:5:26 | EnvKey | test.js:5:9:5:39 | EnvKey |
|
||||
| test.js:5:32:5:39 | req.body | test.js:5:9:5:28 | { EnvValue, EnvKey } |
|
||||
| test.js:5:32:5:39 | req.body | test.js:5:9:5:28 | { EnvValue, EnvKey } |
|
||||
| test.js:13:9:13:28 | { EnvValue, EnvKey } | test.js:13:11:13:18 | EnvValue |
|
||||
| test.js:13:9:13:28 | { EnvValue, EnvKey } | test.js:13:21:13:26 | EnvKey |
|
||||
| test.js:13:9:13:39 | EnvKey | test.js:15:15:15:20 | EnvKey |
|
||||
| test.js:13:9:13:39 | EnvKey | test.js:15:15:15:20 | EnvKey |
|
||||
| test.js:13:9:13:39 | EnvValue | test.js:16:26:16:33 | EnvValue |
|
||||
| test.js:13:9:13:39 | EnvValue | test.js:16:26:16:33 | EnvValue |
|
||||
| test.js:13:11:13:18 | EnvValue | test.js:13:9:13:39 | EnvValue |
|
||||
| test.js:13:21:13:26 | EnvKey | test.js:13:9:13:39 | EnvKey |
|
||||
| test.js:13:32:13:39 | req.body | test.js:13:9:13:28 | { EnvValue, EnvKey } |
|
||||
| test.js:13:32:13:39 | req.body | test.js:13:9:13:28 | { EnvValue, EnvKey } |
|
||||
#select
|
||||
| test.js:6:15:6:20 | EnvKey | test.js:5:32:5:39 | req.body | test.js:6:15:6:20 | EnvKey | arbitrary environment variable assignment from this $@. | test.js:5:32:5:39 | req.body | user controllable source |
|
||||
| test.js:7:15:7:20 | EnvKey | test.js:5:32:5:39 | req.body | test.js:7:15:7:20 | EnvKey | arbitrary environment variable assignment from this $@. | test.js:5:32:5:39 | req.body | user controllable source |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE-099/EnvValueAndKeyInjection.ql
|
||||
@@ -0,0 +1,19 @@
|
||||
const http = require('node:http');
|
||||
|
||||
|
||||
http.createServer((req, res) => {
|
||||
const { EnvValue, EnvKey } = req.body;
|
||||
process.env[EnvKey] = EnvValue; // NOT OK
|
||||
process.env[EnvKey] = EnvValue; // NOT OK
|
||||
|
||||
res.end('env has been injected!');
|
||||
});
|
||||
|
||||
http.createServer((req, res) => {
|
||||
const { EnvValue, EnvKey } = req.body;
|
||||
|
||||
process.env[EnvKey] = "constant" // OK
|
||||
process.env.constant = EnvValue // OK
|
||||
|
||||
res.end('env has been injected!');
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
nodes
|
||||
| test.js:4:9:4:20 | { EnvValue } |
|
||||
| test.js:4:9:4:31 | EnvValue |
|
||||
| test.js:4:11:4:18 | EnvValue |
|
||||
| test.js:4:24:4:31 | req.body |
|
||||
| test.js:4:24:4:31 | req.body |
|
||||
| test.js:5:35:5:42 | EnvValue |
|
||||
| test.js:5:35:5:42 | EnvValue |
|
||||
| test.js:6:23:6:30 | EnvValue |
|
||||
| test.js:6:23:6:30 | EnvValue |
|
||||
| test.js:7:22:7:29 | EnvValue |
|
||||
| test.js:7:22:7:29 | EnvValue |
|
||||
edges
|
||||
| test.js:4:9:4:20 | { EnvValue } | test.js:4:11:4:18 | EnvValue |
|
||||
| test.js:4:9:4:31 | EnvValue | test.js:5:35:5:42 | EnvValue |
|
||||
| test.js:4:9:4:31 | EnvValue | test.js:5:35:5:42 | EnvValue |
|
||||
| test.js:4:9:4:31 | EnvValue | test.js:6:23:6:30 | EnvValue |
|
||||
| test.js:4:9:4:31 | EnvValue | test.js:6:23:6:30 | EnvValue |
|
||||
| test.js:4:9:4:31 | EnvValue | test.js:7:22:7:29 | EnvValue |
|
||||
| test.js:4:9:4:31 | EnvValue | test.js:7:22:7:29 | EnvValue |
|
||||
| test.js:4:11:4:18 | EnvValue | test.js:4:9:4:31 | EnvValue |
|
||||
| test.js:4:24:4:31 | req.body | test.js:4:9:4:20 | { EnvValue } |
|
||||
| test.js:4:24:4:31 | req.body | test.js:4:9:4:20 | { EnvValue } |
|
||||
#select
|
||||
| test.js:5:35:5:42 | EnvValue | test.js:4:24:4:31 | req.body | test.js:5:35:5:42 | EnvValue | this environment variable assignment is $@. | test.js:4:24:4:31 | req.body | user controllable |
|
||||
| test.js:6:23:6:30 | EnvValue | test.js:4:24:4:31 | req.body | test.js:6:23:6:30 | EnvValue | this environment variable assignment is $@. | test.js:4:24:4:31 | req.body | user controllable |
|
||||
| test.js:7:22:7:29 | EnvValue | test.js:4:24:4:31 | req.body | test.js:7:22:7:29 | EnvValue | this environment variable assignment is $@. | test.js:4:24:4:31 | req.body | user controllable |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE-099/EnvValueInjection.ql
|
||||
@@ -0,0 +1,10 @@
|
||||
const http = require('node:http');
|
||||
|
||||
http.createServer((req, res) => {
|
||||
const { EnvValue } = req.body;
|
||||
process.env["A_Critical_Env"] = EnvValue; // NOT OK
|
||||
process.env[AKey] = EnvValue; // NOT OK
|
||||
process.env.AKey = EnvValue; // NOT OK
|
||||
|
||||
res.end('env has been injected!');
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
const express = require('express')
|
||||
const jwtJsonwebtoken = require('jsonwebtoken');
|
||||
|
||||
function getSecret() {
|
||||
return "A Safe generated random key"
|
||||
}
|
||||
|
||||
function aJWT() {
|
||||
return "A JWT provided by user"
|
||||
}
|
||||
|
||||
(function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// BAD: no signature verification
|
||||
jwtJsonwebtoken.decode(UserToken) // NOT OK
|
||||
})();
|
||||
|
||||
(function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// BAD: no signature verification
|
||||
jwtJsonwebtoken.decode(UserToken) // NOT OK
|
||||
jwtJsonwebtoken.verify(UserToken, getSecret(), { algorithms: ["HS256", "none"] }) // NOT OK
|
||||
})();
|
||||
|
||||
(function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// GOOD: with signature verification
|
||||
jwtJsonwebtoken.verify(UserToken, getSecret()) // OK
|
||||
})();
|
||||
|
||||
(function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// GOOD: first without signature verification then with signature verification for same UserToken
|
||||
jwtJsonwebtoken.decode(UserToken) // OK
|
||||
jwtJsonwebtoken.verify(UserToken, getSecret()) // OK
|
||||
})();
|
||||
|
||||
(function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// GOOD: first without signature verification then with signature verification for same UserToken
|
||||
jwtJsonwebtoken.decode(UserToken) // OK
|
||||
jwtJsonwebtoken.verify(UserToken, getSecret(), { algorithms: ["HS256"] }) // OK
|
||||
})();
|
||||
@@ -0,0 +1,141 @@
|
||||
nodes
|
||||
| JsonWebToken.js:13:11:13:28 | UserToken |
|
||||
| JsonWebToken.js:13:23:13:28 | aJwt() |
|
||||
| JsonWebToken.js:13:23:13:28 | aJwt() |
|
||||
| JsonWebToken.js:16:28:16:36 | UserToken |
|
||||
| JsonWebToken.js:16:28:16:36 | UserToken |
|
||||
| JsonWebToken.js:20:11:20:28 | UserToken |
|
||||
| JsonWebToken.js:20:23:20:28 | aJwt() |
|
||||
| JsonWebToken.js:20:23:20:28 | aJwt() |
|
||||
| JsonWebToken.js:23:28:23:36 | UserToken |
|
||||
| JsonWebToken.js:23:28:23:36 | UserToken |
|
||||
| JsonWebToken.js:24:28:24:36 | UserToken |
|
||||
| JsonWebToken.js:24:28:24:36 | UserToken |
|
||||
| JsonWebToken.js:28:11:28:28 | UserToken |
|
||||
| JsonWebToken.js:28:23:28:28 | aJwt() |
|
||||
| JsonWebToken.js:28:23:28:28 | aJwt() |
|
||||
| JsonWebToken.js:31:28:31:36 | UserToken |
|
||||
| JsonWebToken.js:31:28:31:36 | UserToken |
|
||||
| JsonWebToken.js:35:11:35:28 | UserToken |
|
||||
| JsonWebToken.js:35:23:35:28 | aJwt() |
|
||||
| JsonWebToken.js:35:23:35:28 | aJwt() |
|
||||
| JsonWebToken.js:38:28:38:36 | UserToken |
|
||||
| JsonWebToken.js:38:28:38:36 | UserToken |
|
||||
| JsonWebToken.js:39:28:39:36 | UserToken |
|
||||
| JsonWebToken.js:39:28:39:36 | UserToken |
|
||||
| JsonWebToken.js:43:11:43:28 | UserToken |
|
||||
| JsonWebToken.js:43:23:43:28 | aJwt() |
|
||||
| JsonWebToken.js:43:23:43:28 | aJwt() |
|
||||
| JsonWebToken.js:46:28:46:36 | UserToken |
|
||||
| JsonWebToken.js:46:28:46:36 | UserToken |
|
||||
| JsonWebToken.js:47:28:47:36 | UserToken |
|
||||
| JsonWebToken.js:47:28:47:36 | UserToken |
|
||||
| jose.js:12:11:12:28 | UserToken |
|
||||
| jose.js:12:23:12:28 | aJwt() |
|
||||
| jose.js:12:23:12:28 | aJwt() |
|
||||
| jose.js:15:20:15:28 | UserToken |
|
||||
| jose.js:15:20:15:28 | UserToken |
|
||||
| jose.js:19:11:19:28 | UserToken |
|
||||
| jose.js:19:23:19:28 | aJwt() |
|
||||
| jose.js:19:23:19:28 | aJwt() |
|
||||
| jose.js:22:20:22:28 | UserToken |
|
||||
| jose.js:22:20:22:28 | UserToken |
|
||||
| jose.js:23:26:23:34 | UserToken |
|
||||
| jose.js:23:26:23:34 | UserToken |
|
||||
| jose.js:27:11:27:28 | UserToken |
|
||||
| jose.js:27:23:27:28 | aJwt() |
|
||||
| jose.js:27:23:27:28 | aJwt() |
|
||||
| jose.js:30:26:30:34 | UserToken |
|
||||
| jose.js:30:26:30:34 | UserToken |
|
||||
| jwtDecode.js:13:11:13:28 | UserToken |
|
||||
| jwtDecode.js:13:23:13:28 | aJwt() |
|
||||
| jwtDecode.js:13:23:13:28 | aJwt() |
|
||||
| jwtDecode.js:17:16:17:24 | UserToken |
|
||||
| jwtDecode.js:17:16:17:24 | UserToken |
|
||||
| jwtSimple.js:13:11:13:28 | UserToken |
|
||||
| jwtSimple.js:13:23:13:28 | aJwt() |
|
||||
| jwtSimple.js:13:23:13:28 | aJwt() |
|
||||
| jwtSimple.js:16:23:16:31 | UserToken |
|
||||
| jwtSimple.js:16:23:16:31 | UserToken |
|
||||
| jwtSimple.js:20:11:20:28 | UserToken |
|
||||
| jwtSimple.js:20:23:20:28 | aJwt() |
|
||||
| jwtSimple.js:20:23:20:28 | aJwt() |
|
||||
| jwtSimple.js:23:23:23:31 | UserToken |
|
||||
| jwtSimple.js:23:23:23:31 | UserToken |
|
||||
| jwtSimple.js:24:23:24:31 | UserToken |
|
||||
| jwtSimple.js:24:23:24:31 | UserToken |
|
||||
| jwtSimple.js:28:11:28:28 | UserToken |
|
||||
| jwtSimple.js:28:23:28:28 | aJwt() |
|
||||
| jwtSimple.js:28:23:28:28 | aJwt() |
|
||||
| jwtSimple.js:31:23:31:31 | UserToken |
|
||||
| jwtSimple.js:31:23:31:31 | UserToken |
|
||||
| jwtSimple.js:32:23:32:31 | UserToken |
|
||||
| jwtSimple.js:32:23:32:31 | UserToken |
|
||||
edges
|
||||
| JsonWebToken.js:13:11:13:28 | UserToken | JsonWebToken.js:16:28:16:36 | UserToken |
|
||||
| JsonWebToken.js:13:11:13:28 | UserToken | JsonWebToken.js:16:28:16:36 | UserToken |
|
||||
| JsonWebToken.js:13:23:13:28 | aJwt() | JsonWebToken.js:13:11:13:28 | UserToken |
|
||||
| JsonWebToken.js:13:23:13:28 | aJwt() | JsonWebToken.js:13:11:13:28 | UserToken |
|
||||
| JsonWebToken.js:20:11:20:28 | UserToken | JsonWebToken.js:23:28:23:36 | UserToken |
|
||||
| JsonWebToken.js:20:11:20:28 | UserToken | JsonWebToken.js:23:28:23:36 | UserToken |
|
||||
| JsonWebToken.js:20:11:20:28 | UserToken | JsonWebToken.js:24:28:24:36 | UserToken |
|
||||
| JsonWebToken.js:20:11:20:28 | UserToken | JsonWebToken.js:24:28:24:36 | UserToken |
|
||||
| JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:20:11:20:28 | UserToken |
|
||||
| JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:20:11:20:28 | UserToken |
|
||||
| JsonWebToken.js:28:11:28:28 | UserToken | JsonWebToken.js:31:28:31:36 | UserToken |
|
||||
| JsonWebToken.js:28:11:28:28 | UserToken | JsonWebToken.js:31:28:31:36 | UserToken |
|
||||
| JsonWebToken.js:28:23:28:28 | aJwt() | JsonWebToken.js:28:11:28:28 | UserToken |
|
||||
| JsonWebToken.js:28:23:28:28 | aJwt() | JsonWebToken.js:28:11:28:28 | UserToken |
|
||||
| JsonWebToken.js:35:11:35:28 | UserToken | JsonWebToken.js:38:28:38:36 | UserToken |
|
||||
| JsonWebToken.js:35:11:35:28 | UserToken | JsonWebToken.js:38:28:38:36 | UserToken |
|
||||
| JsonWebToken.js:35:11:35:28 | UserToken | JsonWebToken.js:39:28:39:36 | UserToken |
|
||||
| JsonWebToken.js:35:11:35:28 | UserToken | JsonWebToken.js:39:28:39:36 | UserToken |
|
||||
| JsonWebToken.js:35:23:35:28 | aJwt() | JsonWebToken.js:35:11:35:28 | UserToken |
|
||||
| JsonWebToken.js:35:23:35:28 | aJwt() | JsonWebToken.js:35:11:35:28 | UserToken |
|
||||
| JsonWebToken.js:43:11:43:28 | UserToken | JsonWebToken.js:46:28:46:36 | UserToken |
|
||||
| JsonWebToken.js:43:11:43:28 | UserToken | JsonWebToken.js:46:28:46:36 | UserToken |
|
||||
| JsonWebToken.js:43:11:43:28 | UserToken | JsonWebToken.js:47:28:47:36 | UserToken |
|
||||
| JsonWebToken.js:43:11:43:28 | UserToken | JsonWebToken.js:47:28:47:36 | UserToken |
|
||||
| JsonWebToken.js:43:23:43:28 | aJwt() | JsonWebToken.js:43:11:43:28 | UserToken |
|
||||
| JsonWebToken.js:43:23:43:28 | aJwt() | JsonWebToken.js:43:11:43:28 | UserToken |
|
||||
| jose.js:12:11:12:28 | UserToken | jose.js:15:20:15:28 | UserToken |
|
||||
| jose.js:12:11:12:28 | UserToken | jose.js:15:20:15:28 | UserToken |
|
||||
| jose.js:12:23:12:28 | aJwt() | jose.js:12:11:12:28 | UserToken |
|
||||
| jose.js:12:23:12:28 | aJwt() | jose.js:12:11:12:28 | UserToken |
|
||||
| jose.js:19:11:19:28 | UserToken | jose.js:22:20:22:28 | UserToken |
|
||||
| jose.js:19:11:19:28 | UserToken | jose.js:22:20:22:28 | UserToken |
|
||||
| jose.js:19:11:19:28 | UserToken | jose.js:23:26:23:34 | UserToken |
|
||||
| jose.js:19:11:19:28 | UserToken | jose.js:23:26:23:34 | UserToken |
|
||||
| jose.js:19:23:19:28 | aJwt() | jose.js:19:11:19:28 | UserToken |
|
||||
| jose.js:19:23:19:28 | aJwt() | jose.js:19:11:19:28 | UserToken |
|
||||
| jose.js:27:11:27:28 | UserToken | jose.js:30:26:30:34 | UserToken |
|
||||
| jose.js:27:11:27:28 | UserToken | jose.js:30:26:30:34 | UserToken |
|
||||
| jose.js:27:23:27:28 | aJwt() | jose.js:27:11:27:28 | UserToken |
|
||||
| jose.js:27:23:27:28 | aJwt() | jose.js:27:11:27:28 | UserToken |
|
||||
| jwtDecode.js:13:11:13:28 | UserToken | jwtDecode.js:17:16:17:24 | UserToken |
|
||||
| jwtDecode.js:13:11:13:28 | UserToken | jwtDecode.js:17:16:17:24 | UserToken |
|
||||
| jwtDecode.js:13:23:13:28 | aJwt() | jwtDecode.js:13:11:13:28 | UserToken |
|
||||
| jwtDecode.js:13:23:13:28 | aJwt() | jwtDecode.js:13:11:13:28 | UserToken |
|
||||
| jwtSimple.js:13:11:13:28 | UserToken | jwtSimple.js:16:23:16:31 | UserToken |
|
||||
| jwtSimple.js:13:11:13:28 | UserToken | jwtSimple.js:16:23:16:31 | UserToken |
|
||||
| jwtSimple.js:13:23:13:28 | aJwt() | jwtSimple.js:13:11:13:28 | UserToken |
|
||||
| jwtSimple.js:13:23:13:28 | aJwt() | jwtSimple.js:13:11:13:28 | UserToken |
|
||||
| jwtSimple.js:20:11:20:28 | UserToken | jwtSimple.js:23:23:23:31 | UserToken |
|
||||
| jwtSimple.js:20:11:20:28 | UserToken | jwtSimple.js:23:23:23:31 | UserToken |
|
||||
| jwtSimple.js:20:11:20:28 | UserToken | jwtSimple.js:24:23:24:31 | UserToken |
|
||||
| jwtSimple.js:20:11:20:28 | UserToken | jwtSimple.js:24:23:24:31 | UserToken |
|
||||
| jwtSimple.js:20:23:20:28 | aJwt() | jwtSimple.js:20:11:20:28 | UserToken |
|
||||
| jwtSimple.js:20:23:20:28 | aJwt() | jwtSimple.js:20:11:20:28 | UserToken |
|
||||
| jwtSimple.js:28:11:28:28 | UserToken | jwtSimple.js:31:23:31:31 | UserToken |
|
||||
| jwtSimple.js:28:11:28:28 | UserToken | jwtSimple.js:31:23:31:31 | UserToken |
|
||||
| jwtSimple.js:28:11:28:28 | UserToken | jwtSimple.js:32:23:32:31 | UserToken |
|
||||
| jwtSimple.js:28:11:28:28 | UserToken | jwtSimple.js:32:23:32:31 | UserToken |
|
||||
| jwtSimple.js:28:23:28:28 | aJwt() | jwtSimple.js:28:11:28:28 | UserToken |
|
||||
| jwtSimple.js:28:23:28:28 | aJwt() | jwtSimple.js:28:11:28:28 | UserToken |
|
||||
#select
|
||||
| JsonWebToken.js:13:23:13:28 | aJwt() | JsonWebToken.js:13:23:13:28 | aJwt() | JsonWebToken.js:16:28:16:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:16:28:16:36 | UserToken | without signature verification |
|
||||
| JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:23:28:23:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:23:28:23:36 | UserToken | without signature verification |
|
||||
| JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:20:23:20:28 | aJwt() | JsonWebToken.js:24:28:24:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:24:28:24:36 | UserToken | without signature verification |
|
||||
| jose.js:12:23:12:28 | aJwt() | jose.js:12:23:12:28 | aJwt() | jose.js:15:20:15:28 | UserToken | Decoding JWT $@. | jose.js:15:20:15:28 | UserToken | without signature verification |
|
||||
| jwtDecode.js:13:23:13:28 | aJwt() | jwtDecode.js:13:23:13:28 | aJwt() | jwtDecode.js:17:16:17:24 | UserToken | Decoding JWT $@. | jwtDecode.js:17:16:17:24 | UserToken | without signature verification |
|
||||
| jwtSimple.js:13:23:13:28 | aJwt() | jwtSimple.js:13:23:13:28 | aJwt() | jwtSimple.js:16:23:16:31 | UserToken | Decoding JWT $@. | jwtSimple.js:16:23:16:31 | UserToken | without signature verification |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE-347/decodeJwtWithoutVerificationLocalSource.ql
|
||||
@@ -0,0 +1,31 @@
|
||||
const jose = require('jose')
|
||||
|
||||
function getSecret() {
|
||||
return "A Safe generated random key"
|
||||
}
|
||||
|
||||
function aJWT() {
|
||||
return "A JWT provided by user"
|
||||
}
|
||||
|
||||
(function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// no signature verification
|
||||
jose.decodeJwt(UserToken) // NOT OK
|
||||
})();
|
||||
|
||||
(async function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// first without signature verification then with signature verification for same UserToken
|
||||
jose.decodeJwt(UserToken) // OK
|
||||
await jose.jwtVerify(UserToken, new TextEncoder().encode(getSecret())) // OK
|
||||
})();
|
||||
|
||||
(async function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// with signature verification
|
||||
await jose.jwtVerify(UserToken, new TextEncoder().encode(getSecret())) // OK
|
||||
})();
|
||||
@@ -0,0 +1,18 @@
|
||||
const express = require('express')
|
||||
const jwt_decode = require('jwt-decode');
|
||||
|
||||
function getSecret() {
|
||||
return "A Safe generated random key"
|
||||
}
|
||||
|
||||
function aJWT() {
|
||||
return "A JWT provided by user"
|
||||
}
|
||||
|
||||
(function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// jwt-decode
|
||||
// no signature verification
|
||||
jwt_decode(UserToken) // NOT OK
|
||||
})();
|
||||
@@ -0,0 +1,33 @@
|
||||
const express = require('express')
|
||||
const jwt_simple = require('jwt-simple');
|
||||
|
||||
function getSecret() {
|
||||
return "A Safe generated random key"
|
||||
}
|
||||
|
||||
function aJWT() {
|
||||
return "A JWT provided by user"
|
||||
}
|
||||
|
||||
(function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// BAD: no signature verification
|
||||
jwt_simple.decode(UserToken, getSecret(), true); // NOT OK
|
||||
})();
|
||||
|
||||
(function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// GOOD: all with with signature verification
|
||||
jwt_simple.decode(UserToken, getSecret(), false); // OK
|
||||
jwt_simple.decode(UserToken, getSecret()); // OK
|
||||
})();
|
||||
|
||||
(function () {
|
||||
const UserToken = aJwt()
|
||||
|
||||
// GOOD: first without signature verification then with signature verification for same UserToken
|
||||
jwt_simple.decode(UserToken, getSecret(), true); // OK
|
||||
jwt_simple.decode(UserToken, getSecret()); // OK
|
||||
})();
|
||||
@@ -0,0 +1,49 @@
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
const jwtJsonwebtoken = require('jsonwebtoken');
|
||||
const port = 3000
|
||||
|
||||
function getSecret() {
|
||||
return "A Safe generated random key"
|
||||
}
|
||||
app.get('/jwtJsonwebtoken1', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
|
||||
// BAD: no signature verification
|
||||
jwtJsonwebtoken.decode(UserToken) // NOT OK
|
||||
})
|
||||
|
||||
app.get('/jwtJsonwebtoken2', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
|
||||
// BAD: no signature verification
|
||||
jwtJsonwebtoken.decode(UserToken) // NOT OK
|
||||
jwtJsonwebtoken.verify(UserToken, getSecret(), { algorithms: ["HS256", "none"] }) // NOT OK
|
||||
})
|
||||
|
||||
app.get('/jwtJsonwebtoken3', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
|
||||
// GOOD: with signature verification
|
||||
jwtJsonwebtoken.verify(UserToken, getSecret()) // OK
|
||||
})
|
||||
|
||||
app.get('/jwtJsonwebtoken4', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
|
||||
// GOOD: first without signature verification then with signature verification for same UserToken
|
||||
jwtJsonwebtoken.decode(UserToken) // OK
|
||||
jwtJsonwebtoken.verify(UserToken, getSecret()) // OK
|
||||
})
|
||||
|
||||
app.get('/jwtJsonwebtoken5', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
|
||||
// GOOD: first without signature verification then with signature verification for same UserToken
|
||||
jwtJsonwebtoken.decode(UserToken) // OK
|
||||
jwtJsonwebtoken.verify(UserToken, getSecret(), { algorithms: ["HS256"] }) // OK
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Example app listening on port ${port}`)
|
||||
})
|
||||
@@ -0,0 +1,161 @@
|
||||
nodes
|
||||
| JsonWebToken.js:10:11:10:47 | UserToken |
|
||||
| JsonWebToken.js:10:23:10:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:10:23:10:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:13:28:13:36 | UserToken |
|
||||
| JsonWebToken.js:13:28:13:36 | UserToken |
|
||||
| JsonWebToken.js:17:11:17:47 | UserToken |
|
||||
| JsonWebToken.js:17:23:17:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:17:23:17:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:20:28:20:36 | UserToken |
|
||||
| JsonWebToken.js:20:28:20:36 | UserToken |
|
||||
| JsonWebToken.js:21:28:21:36 | UserToken |
|
||||
| JsonWebToken.js:21:28:21:36 | UserToken |
|
||||
| JsonWebToken.js:25:11:25:47 | UserToken |
|
||||
| JsonWebToken.js:25:23:25:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:25:23:25:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:28:28:28:36 | UserToken |
|
||||
| JsonWebToken.js:28:28:28:36 | UserToken |
|
||||
| JsonWebToken.js:32:11:32:47 | UserToken |
|
||||
| JsonWebToken.js:32:11:32:47 | UserToken |
|
||||
| JsonWebToken.js:32:23:32:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:32:23:32:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:32:23:32:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:32:23:32:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:35:28:35:36 | UserToken |
|
||||
| JsonWebToken.js:35:28:35:36 | UserToken |
|
||||
| JsonWebToken.js:36:28:36:36 | UserToken |
|
||||
| JsonWebToken.js:36:28:36:36 | UserToken |
|
||||
| JsonWebToken.js:40:11:40:47 | UserToken |
|
||||
| JsonWebToken.js:40:11:40:47 | UserToken |
|
||||
| JsonWebToken.js:40:23:40:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:40:23:40:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:40:23:40:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:40:23:40:47 | req.hea ... ization |
|
||||
| JsonWebToken.js:43:28:43:36 | UserToken |
|
||||
| JsonWebToken.js:43:28:43:36 | UserToken |
|
||||
| JsonWebToken.js:44:28:44:36 | UserToken |
|
||||
| JsonWebToken.js:44:28:44:36 | UserToken |
|
||||
| jose.js:11:11:11:47 | UserToken |
|
||||
| jose.js:11:23:11:47 | req.hea ... ization |
|
||||
| jose.js:11:23:11:47 | req.hea ... ization |
|
||||
| jose.js:13:20:13:28 | UserToken |
|
||||
| jose.js:13:20:13:28 | UserToken |
|
||||
| jose.js:18:11:18:47 | UserToken |
|
||||
| jose.js:18:23:18:47 | req.hea ... ization |
|
||||
| jose.js:18:23:18:47 | req.hea ... ization |
|
||||
| jose.js:20:26:20:34 | UserToken |
|
||||
| jose.js:20:26:20:34 | UserToken |
|
||||
| jose.js:24:11:24:47 | UserToken |
|
||||
| jose.js:24:11:24:47 | UserToken |
|
||||
| jose.js:24:23:24:47 | req.hea ... ization |
|
||||
| jose.js:24:23:24:47 | req.hea ... ization |
|
||||
| jose.js:24:23:24:47 | req.hea ... ization |
|
||||
| jose.js:24:23:24:47 | req.hea ... ization |
|
||||
| jose.js:26:20:26:28 | UserToken |
|
||||
| jose.js:26:20:26:28 | UserToken |
|
||||
| jose.js:27:26:27:34 | UserToken |
|
||||
| jose.js:27:26:27:34 | UserToken |
|
||||
| jwtDecode.js:11:11:11:47 | UserToken |
|
||||
| jwtDecode.js:11:23:11:47 | req.hea ... ization |
|
||||
| jwtDecode.js:11:23:11:47 | req.hea ... ization |
|
||||
| jwtDecode.js:15:16:15:24 | UserToken |
|
||||
| jwtDecode.js:15:16:15:24 | UserToken |
|
||||
| jwtSimple.js:10:11:10:47 | UserToken |
|
||||
| jwtSimple.js:10:23:10:47 | req.hea ... ization |
|
||||
| jwtSimple.js:10:23:10:47 | req.hea ... ization |
|
||||
| jwtSimple.js:13:23:13:31 | UserToken |
|
||||
| jwtSimple.js:13:23:13:31 | UserToken |
|
||||
| jwtSimple.js:17:11:17:47 | UserToken |
|
||||
| jwtSimple.js:17:23:17:47 | req.hea ... ization |
|
||||
| jwtSimple.js:17:23:17:47 | req.hea ... ization |
|
||||
| jwtSimple.js:20:23:20:31 | UserToken |
|
||||
| jwtSimple.js:20:23:20:31 | UserToken |
|
||||
| jwtSimple.js:21:23:21:31 | UserToken |
|
||||
| jwtSimple.js:21:23:21:31 | UserToken |
|
||||
| jwtSimple.js:25:11:25:47 | UserToken |
|
||||
| jwtSimple.js:25:11:25:47 | UserToken |
|
||||
| jwtSimple.js:25:23:25:47 | req.hea ... ization |
|
||||
| jwtSimple.js:25:23:25:47 | req.hea ... ization |
|
||||
| jwtSimple.js:25:23:25:47 | req.hea ... ization |
|
||||
| jwtSimple.js:25:23:25:47 | req.hea ... ization |
|
||||
| jwtSimple.js:28:23:28:31 | UserToken |
|
||||
| jwtSimple.js:28:23:28:31 | UserToken |
|
||||
| jwtSimple.js:29:23:29:31 | UserToken |
|
||||
| jwtSimple.js:29:23:29:31 | UserToken |
|
||||
edges
|
||||
| JsonWebToken.js:10:11:10:47 | UserToken | JsonWebToken.js:13:28:13:36 | UserToken |
|
||||
| JsonWebToken.js:10:11:10:47 | UserToken | JsonWebToken.js:13:28:13:36 | UserToken |
|
||||
| JsonWebToken.js:10:23:10:47 | req.hea ... ization | JsonWebToken.js:10:11:10:47 | UserToken |
|
||||
| JsonWebToken.js:10:23:10:47 | req.hea ... ization | JsonWebToken.js:10:11:10:47 | UserToken |
|
||||
| JsonWebToken.js:17:11:17:47 | UserToken | JsonWebToken.js:20:28:20:36 | UserToken |
|
||||
| JsonWebToken.js:17:11:17:47 | UserToken | JsonWebToken.js:20:28:20:36 | UserToken |
|
||||
| JsonWebToken.js:17:11:17:47 | UserToken | JsonWebToken.js:21:28:21:36 | UserToken |
|
||||
| JsonWebToken.js:17:11:17:47 | UserToken | JsonWebToken.js:21:28:21:36 | UserToken |
|
||||
| JsonWebToken.js:17:23:17:47 | req.hea ... ization | JsonWebToken.js:17:11:17:47 | UserToken |
|
||||
| JsonWebToken.js:17:23:17:47 | req.hea ... ization | JsonWebToken.js:17:11:17:47 | UserToken |
|
||||
| JsonWebToken.js:25:11:25:47 | UserToken | JsonWebToken.js:28:28:28:36 | UserToken |
|
||||
| JsonWebToken.js:25:11:25:47 | UserToken | JsonWebToken.js:28:28:28:36 | UserToken |
|
||||
| JsonWebToken.js:25:23:25:47 | req.hea ... ization | JsonWebToken.js:25:11:25:47 | UserToken |
|
||||
| JsonWebToken.js:25:23:25:47 | req.hea ... ization | JsonWebToken.js:25:11:25:47 | UserToken |
|
||||
| JsonWebToken.js:32:11:32:47 | UserToken | JsonWebToken.js:35:28:35:36 | UserToken |
|
||||
| JsonWebToken.js:32:11:32:47 | UserToken | JsonWebToken.js:35:28:35:36 | UserToken |
|
||||
| JsonWebToken.js:32:11:32:47 | UserToken | JsonWebToken.js:36:28:36:36 | UserToken |
|
||||
| JsonWebToken.js:32:11:32:47 | UserToken | JsonWebToken.js:36:28:36:36 | UserToken |
|
||||
| JsonWebToken.js:32:23:32:47 | req.hea ... ization | JsonWebToken.js:32:11:32:47 | UserToken |
|
||||
| JsonWebToken.js:32:23:32:47 | req.hea ... ization | JsonWebToken.js:32:11:32:47 | UserToken |
|
||||
| JsonWebToken.js:32:23:32:47 | req.hea ... ization | JsonWebToken.js:32:11:32:47 | UserToken |
|
||||
| JsonWebToken.js:32:23:32:47 | req.hea ... ization | JsonWebToken.js:32:11:32:47 | UserToken |
|
||||
| JsonWebToken.js:40:11:40:47 | UserToken | JsonWebToken.js:43:28:43:36 | UserToken |
|
||||
| JsonWebToken.js:40:11:40:47 | UserToken | JsonWebToken.js:43:28:43:36 | UserToken |
|
||||
| JsonWebToken.js:40:11:40:47 | UserToken | JsonWebToken.js:44:28:44:36 | UserToken |
|
||||
| JsonWebToken.js:40:11:40:47 | UserToken | JsonWebToken.js:44:28:44:36 | UserToken |
|
||||
| JsonWebToken.js:40:23:40:47 | req.hea ... ization | JsonWebToken.js:40:11:40:47 | UserToken |
|
||||
| JsonWebToken.js:40:23:40:47 | req.hea ... ization | JsonWebToken.js:40:11:40:47 | UserToken |
|
||||
| JsonWebToken.js:40:23:40:47 | req.hea ... ization | JsonWebToken.js:40:11:40:47 | UserToken |
|
||||
| JsonWebToken.js:40:23:40:47 | req.hea ... ization | JsonWebToken.js:40:11:40:47 | UserToken |
|
||||
| jose.js:11:11:11:47 | UserToken | jose.js:13:20:13:28 | UserToken |
|
||||
| jose.js:11:11:11:47 | UserToken | jose.js:13:20:13:28 | UserToken |
|
||||
| jose.js:11:23:11:47 | req.hea ... ization | jose.js:11:11:11:47 | UserToken |
|
||||
| jose.js:11:23:11:47 | req.hea ... ization | jose.js:11:11:11:47 | UserToken |
|
||||
| jose.js:18:11:18:47 | UserToken | jose.js:20:26:20:34 | UserToken |
|
||||
| jose.js:18:11:18:47 | UserToken | jose.js:20:26:20:34 | UserToken |
|
||||
| jose.js:18:23:18:47 | req.hea ... ization | jose.js:18:11:18:47 | UserToken |
|
||||
| jose.js:18:23:18:47 | req.hea ... ization | jose.js:18:11:18:47 | UserToken |
|
||||
| jose.js:24:11:24:47 | UserToken | jose.js:26:20:26:28 | UserToken |
|
||||
| jose.js:24:11:24:47 | UserToken | jose.js:26:20:26:28 | UserToken |
|
||||
| jose.js:24:11:24:47 | UserToken | jose.js:27:26:27:34 | UserToken |
|
||||
| jose.js:24:11:24:47 | UserToken | jose.js:27:26:27:34 | UserToken |
|
||||
| jose.js:24:23:24:47 | req.hea ... ization | jose.js:24:11:24:47 | UserToken |
|
||||
| jose.js:24:23:24:47 | req.hea ... ization | jose.js:24:11:24:47 | UserToken |
|
||||
| jose.js:24:23:24:47 | req.hea ... ization | jose.js:24:11:24:47 | UserToken |
|
||||
| jose.js:24:23:24:47 | req.hea ... ization | jose.js:24:11:24:47 | UserToken |
|
||||
| jwtDecode.js:11:11:11:47 | UserToken | jwtDecode.js:15:16:15:24 | UserToken |
|
||||
| jwtDecode.js:11:11:11:47 | UserToken | jwtDecode.js:15:16:15:24 | UserToken |
|
||||
| jwtDecode.js:11:23:11:47 | req.hea ... ization | jwtDecode.js:11:11:11:47 | UserToken |
|
||||
| jwtDecode.js:11:23:11:47 | req.hea ... ization | jwtDecode.js:11:11:11:47 | UserToken |
|
||||
| jwtSimple.js:10:11:10:47 | UserToken | jwtSimple.js:13:23:13:31 | UserToken |
|
||||
| jwtSimple.js:10:11:10:47 | UserToken | jwtSimple.js:13:23:13:31 | UserToken |
|
||||
| jwtSimple.js:10:23:10:47 | req.hea ... ization | jwtSimple.js:10:11:10:47 | UserToken |
|
||||
| jwtSimple.js:10:23:10:47 | req.hea ... ization | jwtSimple.js:10:11:10:47 | UserToken |
|
||||
| jwtSimple.js:17:11:17:47 | UserToken | jwtSimple.js:20:23:20:31 | UserToken |
|
||||
| jwtSimple.js:17:11:17:47 | UserToken | jwtSimple.js:20:23:20:31 | UserToken |
|
||||
| jwtSimple.js:17:11:17:47 | UserToken | jwtSimple.js:21:23:21:31 | UserToken |
|
||||
| jwtSimple.js:17:11:17:47 | UserToken | jwtSimple.js:21:23:21:31 | UserToken |
|
||||
| jwtSimple.js:17:23:17:47 | req.hea ... ization | jwtSimple.js:17:11:17:47 | UserToken |
|
||||
| jwtSimple.js:17:23:17:47 | req.hea ... ization | jwtSimple.js:17:11:17:47 | UserToken |
|
||||
| jwtSimple.js:25:11:25:47 | UserToken | jwtSimple.js:28:23:28:31 | UserToken |
|
||||
| jwtSimple.js:25:11:25:47 | UserToken | jwtSimple.js:28:23:28:31 | UserToken |
|
||||
| jwtSimple.js:25:11:25:47 | UserToken | jwtSimple.js:29:23:29:31 | UserToken |
|
||||
| jwtSimple.js:25:11:25:47 | UserToken | jwtSimple.js:29:23:29:31 | UserToken |
|
||||
| jwtSimple.js:25:23:25:47 | req.hea ... ization | jwtSimple.js:25:11:25:47 | UserToken |
|
||||
| jwtSimple.js:25:23:25:47 | req.hea ... ization | jwtSimple.js:25:11:25:47 | UserToken |
|
||||
| jwtSimple.js:25:23:25:47 | req.hea ... ization | jwtSimple.js:25:11:25:47 | UserToken |
|
||||
| jwtSimple.js:25:23:25:47 | req.hea ... ization | jwtSimple.js:25:11:25:47 | UserToken |
|
||||
#select
|
||||
| JsonWebToken.js:10:23:10:47 | req.hea ... ization | JsonWebToken.js:10:23:10:47 | req.hea ... ization | JsonWebToken.js:13:28:13:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:13:28:13:36 | UserToken | without signature verification |
|
||||
| JsonWebToken.js:17:23:17:47 | req.hea ... ization | JsonWebToken.js:17:23:17:47 | req.hea ... ization | JsonWebToken.js:20:28:20:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:20:28:20:36 | UserToken | without signature verification |
|
||||
| JsonWebToken.js:17:23:17:47 | req.hea ... ization | JsonWebToken.js:17:23:17:47 | req.hea ... ization | JsonWebToken.js:21:28:21:36 | UserToken | Decoding JWT $@. | JsonWebToken.js:21:28:21:36 | UserToken | without signature verification |
|
||||
| jose.js:11:23:11:47 | req.hea ... ization | jose.js:11:23:11:47 | req.hea ... ization | jose.js:13:20:13:28 | UserToken | Decoding JWT $@. | jose.js:13:20:13:28 | UserToken | without signature verification |
|
||||
| jwtDecode.js:11:23:11:47 | req.hea ... ization | jwtDecode.js:11:23:11:47 | req.hea ... ization | jwtDecode.js:15:16:15:24 | UserToken | Decoding JWT $@. | jwtDecode.js:15:16:15:24 | UserToken | without signature verification |
|
||||
| jwtSimple.js:10:23:10:47 | req.hea ... ization | jwtSimple.js:10:23:10:47 | req.hea ... ization | jwtSimple.js:13:23:13:31 | UserToken | Decoding JWT $@. | jwtSimple.js:13:23:13:31 | UserToken | without signature verification |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE-347/decodeJwtWithoutVerification.ql
|
||||
@@ -0,0 +1,32 @@
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
const jose = require('jose')
|
||||
const port = 3000
|
||||
|
||||
function getSecret() {
|
||||
return "A Safe generated random key"
|
||||
}
|
||||
|
||||
app.get('/jose1', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// no signature verification
|
||||
jose.decodeJwt(UserToken) // NOT OK
|
||||
})
|
||||
|
||||
|
||||
app.get('/jose2', async (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// with signature verification
|
||||
await jose.jwtVerify(UserToken, new TextEncoder().encode(getSecret())) // OK
|
||||
})
|
||||
|
||||
app.get('/jose3', async (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
// first without signature verification then with signature verification for same UserToken
|
||||
jose.decodeJwt(UserToken) // OK
|
||||
await jose.jwtVerify(UserToken, new TextEncoder().encode(getSecret())) // OK
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Example app listening on port ${port}`)
|
||||
})
|
||||
@@ -0,0 +1,20 @@
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
const jwt_decode = require('jwt-decode');
|
||||
const port = 3000
|
||||
|
||||
function getSecret() {
|
||||
return "A Safe generated random key"
|
||||
}
|
||||
|
||||
app.get('/jwtDecode', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
|
||||
// jwt-decode
|
||||
// no signature verification
|
||||
jwt_decode(UserToken) // NOT OK
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Example app listening on port ${port}`)
|
||||
})
|
||||
@@ -0,0 +1,34 @@
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
const jwt_simple = require('jwt-simple');
|
||||
const port = 3000
|
||||
|
||||
function getSecret() {
|
||||
return "A Safe generated random key"
|
||||
}
|
||||
app.get('/jwtSimple1', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
|
||||
// no signature verification
|
||||
jwt_simple.decode(UserToken, getSecret(), true); // NOT OK
|
||||
})
|
||||
|
||||
app.get('/jwtSimple2', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
|
||||
// GOOD: all with with signature verification
|
||||
jwt_simple.decode(UserToken, getSecret(), false); // OK
|
||||
jwt_simple.decode(UserToken, getSecret()); // OK
|
||||
})
|
||||
|
||||
app.get('/jwtSimple3', (req, res) => {
|
||||
const UserToken = req.headers.authorization;
|
||||
|
||||
// GOOD: first without signature verification then with signature verification for same UserToken
|
||||
jwt_simple.decode(UserToken, getSecret(), true); // OK
|
||||
jwt_simple.decode(UserToken, getSecret()); // OK
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Example app listening on port ${port}`)
|
||||
})
|
||||
@@ -3,20 +3,22 @@
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:15:27:15:27 | e |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:16:23:16:23 | e |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:20:8:20:16 | arr.pop() |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:52:10:52:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:56:10:56:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:60:10:60:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:66:10:66:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:71:10:71:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:74:8:74:29 | arr.fin ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:77:8:77:35 | arrayFi ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:81:10:81:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:84:8:84:17 | arr.at(-1) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:39:8:39:24 | arr4_spread.pop() |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:61:10:61:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:65:10:65:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:69:10:69:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:75:10:75:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:80:10:80:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:83:8:83:29 | arr.fin ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:86:8:86:35 | arrayFi ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:90:10:90:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:93:8:93:17 | arr.at(-1) |
|
||||
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
|
||||
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
|
||||
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:30:8:30:17 | arr4.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:33:8:33:17 | arr5.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:35:8:35:26 | arr5.slice(2).pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:41:8:41:17 | arr6.pop() |
|
||||
| arrays.js:44:4:44:11 | "source" | arrays.js:45:10:45:18 | ary.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:42:8:42:17 | arr5.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:44:8:44:26 | arr5.slice(2).pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:50:8:50:17 | arr6.pop() |
|
||||
| arrays.js:33:37:33:44 | "source" | arrays.js:35:8:35:25 | arr4_variant.pop() |
|
||||
| arrays.js:53:4:53:11 | "source" | arrays.js:54:10:54:18 | ary.pop() |
|
||||
|
||||
@@ -3,24 +3,26 @@
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:15:27:15:27 | e |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:16:23:16:23 | e |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:20:8:20:16 | arr.pop() |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:49:8:49:13 | arr[0] |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:52:10:52:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:56:10:56:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:60:10:60:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:66:10:66:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:71:10:71:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:74:8:74:29 | arr.fin ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:77:8:77:35 | arrayFi ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:81:10:81:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:84:8:84:17 | arr.at(-1) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:39:8:39:24 | arr4_spread.pop() |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:58:8:58:13 | arr[0] |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:61:10:61:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:65:10:65:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:69:10:69:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:75:10:75:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:80:10:80:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:83:8:83:29 | arr.fin ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:86:8:86:35 | arrayFi ... llback) |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:90:10:90:10 | x |
|
||||
| arrays.js:2:16:2:23 | "source" | arrays.js:93:8:93:17 | arr.at(-1) |
|
||||
| arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e |
|
||||
| arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() |
|
||||
| arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:30:8:30:17 | arr4.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:33:8:33:17 | arr5.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:35:8:35:26 | arr5.slice(2).pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:41:8:41:17 | arr6.pop() |
|
||||
| arrays.js:44:4:44:11 | "source" | arrays.js:45:10:45:18 | ary.pop() |
|
||||
| arrays.js:44:4:44:11 | "source" | arrays.js:46:10:46:12 | ary |
|
||||
| arrays.js:86:9:86:16 | "source" | arrays.js:86:8:86:34 | ["sourc ... ) => x) |
|
||||
| arrays.js:87:9:87:16 | "source" | arrays.js:87:8:87:36 | ["sourc ... => !!x) |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:42:8:42:17 | arr5.pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:44:8:44:26 | arr5.slice(2).pop() |
|
||||
| arrays.js:29:21:29:28 | "source" | arrays.js:50:8:50:17 | arr6.pop() |
|
||||
| arrays.js:33:37:33:44 | "source" | arrays.js:35:8:35:25 | arr4_variant.pop() |
|
||||
| arrays.js:53:4:53:11 | "source" | arrays.js:54:10:54:18 | ary.pop() |
|
||||
| arrays.js:53:4:53:11 | "source" | arrays.js:55:10:55:12 | ary |
|
||||
| arrays.js:95:9:95:16 | "source" | arrays.js:95:8:95:34 | ["sourc ... ) => x) |
|
||||
| arrays.js:96:9:96:16 | "source" | arrays.js:96:8:96:36 | ["sourc ... => !!x) |
|
||||
|
||||
@@ -29,6 +29,15 @@
|
||||
arr4.splice(0, 0, "source");
|
||||
sink(arr4.pop()); // NOT OK
|
||||
|
||||
var arr4_variant = [];
|
||||
arr4_variant.splice(0, 0, "safe", "source");
|
||||
arr4_variant.pop();
|
||||
sink(arr4_variant.pop()); // NOT OK
|
||||
|
||||
var arr4_spread = [];
|
||||
arr4_spread.splice(0, 0, ...arr);
|
||||
sink(arr4_spread.pop()); // NOT OK
|
||||
|
||||
var arr5 = [].concat(arr4);
|
||||
sink(arr5.pop()); // NOT OK
|
||||
|
||||
@@ -46,7 +55,7 @@
|
||||
sink(ary); // OK - its the array itself, not an element.
|
||||
});
|
||||
|
||||
sink(arr[0]); // OK - tuple like usage.
|
||||
sink(arr[0]); // OK - tuple like usage.
|
||||
|
||||
for (const x of arr) {
|
||||
sink(x); // NOT OK
|
||||
@@ -59,7 +68,7 @@
|
||||
for (const x of [...arr]) {
|
||||
sink(x); // NOT OK
|
||||
}
|
||||
|
||||
|
||||
var arr7 = [];
|
||||
arr7.push(...arr);
|
||||
for (const x of arr7) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@ typeTracking
|
||||
| tst.js:2:16:2:23 | source() | tst.js:37:14:37:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:41:14:41:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:45:14:45:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:49:14:49:14 | e |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:53:8:53:21 | map.get("key") |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:59:8:59:22 | map2.get("foo") |
|
||||
| tst.js:2:16:2:23 | source() | tst.js:64:8:64:26 | map3.get(unknown()) |
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
|
||||
for (const e of Array.from(set)) {
|
||||
sink(e); // NOT OK (not caught by type-tracking, as it doesn't include array steps).
|
||||
sink(e); // NOT OK
|
||||
}
|
||||
|
||||
sink(map.get("key")); // NOT OK.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
WARNING: Unused method getMethod (query2.ql:31,14-23)
|
||||
WARNING: Unused method getResponse (query2.ql:45,13-24)
|
||||
WARNING: unused method 'getMethod' (query2.ql:31,14-23)
|
||||
WARNING: unused method 'getResponse' (query2.ql:45,13-24)
|
||||
| robonode/src/assets/raml/api.raml:8:3:72:14 | get: | /robots |
|
||||
| robonode/src/assets/raml/api.raml:15:5:72:14 | uriParameters: | /robots/{robotId} |
|
||||
| robonode/src/assets/raml/api.raml:24:7:54:4 | get: | /robots/{robotId}/commands |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
WARNING: Unused method getMethod (query3.ql:31,14-23)
|
||||
WARNING: unused method 'getMethod' (query3.ql:31,14-23)
|
||||
| 1 |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
WARNING: Unused method getMethod (query4.ql:31,14-23)
|
||||
WARNING: Unused method getResponse (query4.ql:45,13-24)
|
||||
WARNING: unused method 'getMethod' (query4.ql:31,14-23)
|
||||
WARNING: unused method 'getResponse' (query4.ql:45,13-24)
|
||||
| robonode/src/assets/raml/api.raml:9:5:14:2 | description: \| |
|
||||
| robonode/src/assets/raml/api.raml:25:9:29:6 | description: \| |
|
||||
| robonode/src/assets/raml/api.raml:30:9:54:4 | description: \| |
|
||||
|
||||
Reference in New Issue
Block a user