mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
Merge branch 'main' into js-followMsg
This commit is contained in:
4
javascript/ql/lib/change-notes/2022-08-09-mermaid.md
Normal file
4
javascript/ql/lib/change-notes/2022-08-09-mermaid.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* A model for the `mermaid` library has been added. XSS queries can now detect flow through the `render` method of the `mermaid` library.
|
||||
@@ -1495,7 +1495,7 @@ module API {
|
||||
/** Gets the EntryPoint associated with this label. */
|
||||
API::EntryPoint getEntryPoint() { result = e }
|
||||
|
||||
override string toString() { result = "getASuccessor(Label::entryPoint(\"" + e + "\"))" }
|
||||
override string toString() { result = "entryPoint(\"" + e + "\")" }
|
||||
}
|
||||
|
||||
/** A label that gets a promised value. */
|
||||
|
||||
@@ -10,6 +10,11 @@ private import javascript
|
||||
private import semmle.javascript.dataflow.TypeTracking
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
|
||||
/**
|
||||
* An alias for `SourceNode`.
|
||||
*/
|
||||
class LocalSourceNode = SourceNode;
|
||||
|
||||
/**
|
||||
* A source node for local data flow, that is, a node from which local data flow is tracked.
|
||||
*
|
||||
|
||||
@@ -78,6 +78,32 @@ module Markdown {
|
||||
}
|
||||
}
|
||||
|
||||
/** A taint step for the `mermaid` library. */
|
||||
private class MermaidStep extends MarkdownStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(API::CallNode call |
|
||||
call =
|
||||
[API::moduleImport("mermaid"), API::moduleImport("mermaid").getMember("mermaidAPI")]
|
||||
.getMember("render")
|
||||
.getACall()
|
||||
|
|
||||
succ = [call, call.getParameter(2).getParameter(0).asSource()] and
|
||||
pred = call.getArgument(1)
|
||||
)
|
||||
or
|
||||
exists(DataFlow::CallNode call |
|
||||
call =
|
||||
[
|
||||
DataFlow::globalVarRef("mermaid"),
|
||||
DataFlow::globalVarRef("mermaid").getAPropertyRead("mermaidAPI")
|
||||
].getAMemberCall("render")
|
||||
|
|
||||
succ = [call.(DataFlow::Node), call.getABoundCallbackParameter(2, 0)] and
|
||||
pred = call.getArgument(1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Classes and predicates for modeling taint steps in `unified` and `remark`.
|
||||
*/
|
||||
|
||||
@@ -72,6 +72,8 @@ private class Unit = Specific::Unit;
|
||||
|
||||
private module API = Specific::API;
|
||||
|
||||
private module DataFlow = Specific::DataFlow;
|
||||
|
||||
private import Specific::AccessPathSyntax
|
||||
|
||||
/** Module containing hooks for providing input data to be interpreted as a model. */
|
||||
@@ -156,6 +158,22 @@ module ModelInput {
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional type model rows from CodeQL models.
|
||||
*/
|
||||
class TypeModel extends Unit {
|
||||
/**
|
||||
* Gets a data-flow node that is a source of the type `package;type`.
|
||||
*/
|
||||
DataFlow::Node getASource(string package, string type) { none() }
|
||||
|
||||
/**
|
||||
* Gets a data flow node that is a sink of the type `package;type`,
|
||||
* usually because it is an argument passed to a parameter of that type.
|
||||
*/
|
||||
DataFlow::Node getASink(string package, string type) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional type variable model rows.
|
||||
*/
|
||||
@@ -368,6 +386,57 @@ private predicate invocationMatchesCallSiteFilter(Specific::InvokeNode invoke, A
|
||||
Specific::invocationMatchesExtraCallSiteFilter(invoke, token)
|
||||
}
|
||||
|
||||
private class TypeModelUseEntry extends API::EntryPoint {
|
||||
private string package;
|
||||
private string type;
|
||||
|
||||
TypeModelUseEntry() {
|
||||
exists(any(TypeModel tm).getASource(package, type)) and
|
||||
this = "TypeModelUseEntry;" + package + ";" + type
|
||||
}
|
||||
|
||||
override DataFlow::LocalSourceNode getASource() {
|
||||
result = any(TypeModel tm).getASource(package, type)
|
||||
}
|
||||
|
||||
API::Node getNodeForType(string package_, string type_) {
|
||||
package = package_ and type = type_ and result = this.getANode()
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeModelDefEntry extends API::EntryPoint {
|
||||
private string package;
|
||||
private string type;
|
||||
|
||||
TypeModelDefEntry() {
|
||||
exists(any(TypeModel tm).getASink(package, type)) and
|
||||
this = "TypeModelDefEntry;" + package + ";" + type
|
||||
}
|
||||
|
||||
override DataFlow::Node getASink() { result = any(TypeModel tm).getASink(package, type) }
|
||||
|
||||
API::Node getNodeForType(string package_, string type_) {
|
||||
package = package_ and type = type_ and result = this.getANode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an API node identified by the given `(package,type)` pair.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private API::Node getNodeFromType(string package, string type) {
|
||||
exists(string package2, string type2, AccessPath path2 |
|
||||
typeModel(package, type, package2, type2, path2) and
|
||||
result = getNodeFromPath(package2, type2, path2)
|
||||
)
|
||||
or
|
||||
result = any(TypeModelUseEntry e).getNodeForType(package, type)
|
||||
or
|
||||
result = any(TypeModelDefEntry e).getNodeForType(package, type)
|
||||
or
|
||||
result = Specific::getExtraNodeFromType(package, type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the API node identified by the first `n` tokens of `path` in the given `(package, type, path)` tuple.
|
||||
*/
|
||||
@@ -376,12 +445,8 @@ private API::Node getNodeFromPath(string package, string type, AccessPath path,
|
||||
isRelevantFullPath(package, type, path) and
|
||||
(
|
||||
n = 0 and
|
||||
exists(string package2, string type2, AccessPath path2 |
|
||||
typeModel(package, type, package2, type2, path2) and
|
||||
result = getNodeFromPath(package2, type2, path2, path2.getNumToken())
|
||||
)
|
||||
result = getNodeFromType(package, type)
|
||||
or
|
||||
// Language-specific cases, such as handling of global variables
|
||||
result = Specific::getExtraNodeFromPath(package, type, path, n)
|
||||
)
|
||||
or
|
||||
@@ -581,12 +646,7 @@ module ModelOutput {
|
||||
* Holds if `node` is seen as an instance of `(package,type)` due to a type definition
|
||||
* contributed by a CSV model.
|
||||
*/
|
||||
API::Node getATypeNode(string package, string type) {
|
||||
exists(string package2, string type2, AccessPath path |
|
||||
typeModel(package, type, package2, type2, path) and
|
||||
result = getNodeFromPath(package2, type2, path)
|
||||
)
|
||||
}
|
||||
API::Node getATypeNode(string package, string type) { result = getNodeFromType(package, type) }
|
||||
|
||||
/**
|
||||
* Gets an error message relating to an invalid CSV row in a model.
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
|
||||
private import javascript as JS
|
||||
private import JS::DataFlow as DataFlow
|
||||
private import ApiGraphModels
|
||||
|
||||
class Unit = JS::Unit;
|
||||
@@ -29,6 +28,7 @@ class Unit = JS::Unit;
|
||||
module API = JS::API;
|
||||
|
||||
import semmle.javascript.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax
|
||||
import JS::DataFlow as DataFlow
|
||||
private import AccessPathSyntax
|
||||
|
||||
/**
|
||||
@@ -77,10 +77,6 @@ private API::Node getGlobalNode(string globalName) {
|
||||
/** Gets a JavaScript-specific interpretation of the `(package, type, path)` tuple after resolving the first `n` access path tokens. */
|
||||
bindingset[package, type, path]
|
||||
API::Node getExtraNodeFromPath(string package, string type, AccessPath path, int n) {
|
||||
type = "" and
|
||||
n = 0 and
|
||||
result = API::moduleImport(package)
|
||||
or
|
||||
// Global variable accesses is via the 'global' package
|
||||
exists(AccessPathToken token |
|
||||
package = getAPackageAlias("global") and
|
||||
@@ -90,10 +86,15 @@ API::Node getExtraNodeFromPath(string package, string type, AccessPath path, int
|
||||
result = getGlobalNode(token.getAnArgument()) and
|
||||
n = 1
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a JavaScript-specific interpretation of the `(package, type)` tuple. */
|
||||
API::Node getExtraNodeFromType(string package, string type) {
|
||||
type = "" and
|
||||
result = API::moduleImport(package)
|
||||
or
|
||||
// Access instance of a type based on type annotations
|
||||
n = 0 and
|
||||
result = API::Node::ofType(getAPackageAlias(package), type)
|
||||
result = API::Internal::getANodeOfTypeRaw(getAPackageAlias(package), type)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,3 +87,70 @@ module Cryptography {
|
||||
predicate isWeak() { this = "ECB" }
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides classes for modeling HTTP-related APIs. */
|
||||
module Http {
|
||||
/** Provides classes for modeling HTTP clients. */
|
||||
module Client {
|
||||
/**
|
||||
* A data-flow node that makes an outgoing HTTP request.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `Http::Client::Request::Range` instead.
|
||||
*/
|
||||
class Request extends DataFlow::Node instanceof Request::Range {
|
||||
/**
|
||||
* Gets a data-flow node that contributes to the URL of the request.
|
||||
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
|
||||
*/
|
||||
DataFlow::Node getAUrlPart() { result = super.getAUrlPart() }
|
||||
|
||||
/** Gets a string that identifies the framework used for this request. */
|
||||
string getFramework() { result = super.getFramework() }
|
||||
|
||||
/**
|
||||
* Holds if this request is made using a mode that disables SSL/TLS
|
||||
* certificate validation, where `disablingNode` represents the point at
|
||||
* which the validation was disabled, and `argumentOrigin` represents the origin
|
||||
* of the argument that disabled the validation (which could be the same node as
|
||||
* `disablingNode`).
|
||||
*/
|
||||
predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
super.disablesCertificateValidation(disablingNode, argumentOrigin)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP requests. */
|
||||
module Request {
|
||||
/**
|
||||
* A data-flow node that makes an outgoing HTTP request.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `Http::Client::Request` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets a data-flow node that contributes to the URL of the request.
|
||||
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
|
||||
*/
|
||||
abstract DataFlow::Node getAUrlPart();
|
||||
|
||||
/** Gets a string that identifies the framework used for this request. */
|
||||
abstract string getFramework();
|
||||
|
||||
/**
|
||||
* Holds if this request is made using a mode that disables SSL/TLS
|
||||
* certificate validation, where `disablingNode` represents the point at
|
||||
* which the validation was disabled, and `argumentOrigin` represents the origin
|
||||
* of the argument that disabled the validation (which could be the same node as
|
||||
* `disablingNode`).
|
||||
*/
|
||||
abstract predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ module CodeInjection {
|
||||
exists(string callName | c = DataFlow::globalVarRef(callName).getAnInvocation() |
|
||||
callName = "eval" and index = 0
|
||||
or
|
||||
callName = "Function"
|
||||
callName = "Function" and index = -1
|
||||
or
|
||||
callName = "execScript" and index = 0
|
||||
or
|
||||
@@ -186,14 +186,13 @@ module CodeInjection {
|
||||
callName = "setImmediate" and index = 0
|
||||
)
|
||||
or
|
||||
exists(DataFlow::GlobalVarRefNode wasm, string methodName |
|
||||
wasm.getName() = "WebAssembly" and c = wasm.getAMemberCall(methodName)
|
||||
|
|
||||
methodName = "compile" or
|
||||
methodName = "compileStreaming"
|
||||
)
|
||||
c = DataFlow::globalVarRef("WebAssembly").getAMemberCall(["compile", "compileStreaming"]) and
|
||||
index = -1
|
||||
|
|
||||
this = c.getArgument(index)
|
||||
or
|
||||
index = -1 and
|
||||
this = c.getAnArgument()
|
||||
)
|
||||
or
|
||||
// node-serialize is not intended to be safe for untrusted inputs
|
||||
|
||||
@@ -26,7 +26,11 @@ class Configuration extends DataFlow::Configuration {
|
||||
sink.analyze().getAType() = TTObject()
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
|
||||
override predicate isBarrier(DataFlow::Node node) {
|
||||
super.isBarrier(node)
|
||||
or
|
||||
node instanceof Barrier
|
||||
}
|
||||
|
||||
override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) {
|
||||
guard instanceof TypeOfTestBarrier or
|
||||
@@ -50,7 +54,7 @@ private class TypeOfTestBarrier extends DataFlow::BarrierGuardNode, DataFlow::Va
|
||||
}
|
||||
|
||||
private class IsArrayBarrier extends DataFlow::BarrierGuardNode, DataFlow::CallNode {
|
||||
IsArrayBarrier() { this = DataFlow::globalVarRef("Array").getAMemberCall("isArray").getACall() }
|
||||
IsArrayBarrier() { this = DataFlow::globalVarRef("Array").getAMemberCall("isArray") }
|
||||
|
||||
override predicate blocks(boolean outcome, Expr e) {
|
||||
e = getArgument(0).asExpr() and
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* @name Insecure temporary file
|
||||
* @description Creating a temporary file that is accessible by other users TODO:
|
||||
* @description Creating a temporary file that is accessible by other users can
|
||||
* lead to information disclosure and sometimes remote code execution.
|
||||
* @kind path-problem
|
||||
* @id js/insecure-temporary-file
|
||||
* @problem.severity warning
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
|
||||
- Fixed a bug in the `js/type-confusion-through-parameter-tampering` query that would cause it to ignore
|
||||
sanitizers in branching conditions. The query should now report fewer false positives.
|
||||
@@ -1 +1 @@
|
||||
module.exports = CustomEntryPoint.foo; /* use=getASuccessor(Label::entryPoint("CustomEntryPoint")) */
|
||||
module.exports = CustomEntryPoint.foo; /* use=entryPoint("CustomEntryPoint") */
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
| body-parser | | index.ts:4:20:4:41 | require ... arser") |
|
||||
| express | | index.ts:3:17:3:34 | require("express") |
|
||||
| mongodb | | index.ts:1:8:1:19 | * as mongodb |
|
||||
| mongodb | Collection | index.ts:14:3:14:17 | getCollection() |
|
||||
| mongoose | | index.ts:17:8:17:20 | * as mongoose |
|
||||
| mongoose | Model | index.ts:22:3:22:20 | getMongooseModel() |
|
||||
| mongoose | Query | index.ts:23:3:23:20 | getMongooseQuery() |
|
||||
| puppeteer | | index.ts:26:8:26:21 | * as puppeteer |
|
||||
| puppeteer | Browser | index.ts:30:22:30:33 | this.browser |
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
underlyingTypeNode
|
||||
| foo | | file://:0:0:0:0 | use moduleImport("foo").getMember("exports") |
|
||||
| foo | | foo.ts:1:8:1:10 | use moduleImport("foo").getMember("exports").getMember("default") |
|
||||
| foo | Bar | foo.ts:3:1:5:1 | use moduleImport("foo").getMember("exports").getMember("Bar").getInstance() |
|
||||
| foo | Bar | foo.ts:3:12:3:12 | use moduleImport("foo").getMember("exports").getMember("Bar").getInstance() |
|
||||
#select
|
||||
|
||||
@@ -125,7 +125,7 @@ getAffectedStateAccessPath
|
||||
getADispatchFunctionNode
|
||||
| react-redux.jsx:65:20:65:32 | use moduleImport("react-redux").getMember("exports").getMember("useDispatch").getReturn() |
|
||||
getADispatchedValueNode
|
||||
| react-redux.jsx:27:12:30:5 | def getASuccessor(Label::entryPoint("react-redux-connect")).getParameter(1).getMember("manualAction").getReturn() |
|
||||
| react-redux.jsx:27:12:30:5 | def entryPoint("react-redux-connect").getParameter(1).getMember("manualAction").getReturn() |
|
||||
| react-redux.jsx:69:18:69:39 | def moduleImport("react-redux").getMember("exports").getMember("useDispatch").getReturn().getParameter(0) |
|
||||
| react-redux.jsx:70:18:70:38 | def moduleImport("react-redux").getMember("exports").getMember("useDispatch").getReturn().getParameter(0) |
|
||||
getAnUntypedActionInReducer
|
||||
|
||||
@@ -56,6 +56,22 @@ nodes
|
||||
| main.js:93:43:93:43 | x |
|
||||
| main.js:93:43:93:43 | x |
|
||||
| main.js:94:31:94:31 | x |
|
||||
| main.js:98:43:98:43 | x |
|
||||
| main.js:98:43:98:43 | x |
|
||||
| main.js:99:28:99:28 | x |
|
||||
| main.js:99:28:99:28 | x |
|
||||
| main.js:103:43:103:43 | x |
|
||||
| main.js:103:43:103:43 | x |
|
||||
| main.js:105:26:105:26 | x |
|
||||
| main.js:105:26:105:26 | x |
|
||||
| main.js:109:41:109:41 | x |
|
||||
| main.js:109:41:109:41 | x |
|
||||
| main.js:111:37:111:37 | x |
|
||||
| main.js:111:37:111:37 | x |
|
||||
| main.js:116:47:116:47 | s |
|
||||
| main.js:116:47:116:47 | s |
|
||||
| main.js:117:34:117:34 | s |
|
||||
| main.js:117:34:117:34 | s |
|
||||
| typed.ts:1:39:1:39 | s |
|
||||
| typed.ts:1:39:1:39 | s |
|
||||
| typed.ts:2:29:2:29 | s |
|
||||
@@ -126,6 +142,30 @@ edges
|
||||
| main.js:93:43:93:43 | x | main.js:94:31:94:31 | x |
|
||||
| main.js:93:43:93:43 | x | main.js:94:31:94:31 | x |
|
||||
| main.js:94:31:94:31 | x | main.js:89:21:89:21 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:99:28:99:28 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:99:28:99:28 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:99:28:99:28 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:99:28:99:28 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:103:43:103:43 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:103:43:103:43 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:103:43:103:43 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:103:43:103:43 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:105:26:105:26 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:105:26:105:26 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:105:26:105:26 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:105:26:105:26 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:109:41:109:41 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:109:41:109:41 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:109:41:109:41 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:109:41:109:41 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:111:37:111:37 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:111:37:111:37 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:111:37:111:37 | x |
|
||||
| main.js:98:43:98:43 | x | main.js:111:37:111:37 | x |
|
||||
| main.js:116:47:116:47 | s | main.js:117:34:117:34 | s |
|
||||
| main.js:116:47:116:47 | s | main.js:117:34:117:34 | s |
|
||||
| main.js:116:47:116:47 | s | main.js:117:34:117:34 | s |
|
||||
| main.js:116:47:116:47 | s | main.js:117:34:117:34 | s |
|
||||
| typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s |
|
||||
| typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s |
|
||||
| typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s |
|
||||
@@ -153,5 +193,11 @@ edges
|
||||
| main.js:67:63:67:69 | attrVal | main.js:66:35:66:41 | attrVal | main.js:67:63:67:69 | attrVal | $@ which depends on $@ might later cause $@. | main.js:67:63:67:69 | attrVal | HTML construction | main.js:66:35:66:41 | attrVal | library input | main.js:67:47:67:78 | "<img a ... "\\"/>" | cross-site scripting |
|
||||
| main.js:81:35:81:37 | val | main.js:79:34:79:36 | val | main.js:81:35:81:37 | val | $@ which depends on $@ might later cause $@. | main.js:81:35:81:37 | val | HTML construction | main.js:79:34:79:36 | val | library input | main.js:81:24:81:49 | "<span> ... /span>" | cross-site scripting |
|
||||
| main.js:90:23:90:23 | x | main.js:93:43:93:43 | x | main.js:90:23:90:23 | x | $@ which depends on $@ might later cause $@. | main.js:90:23:90:23 | x | HTML construction | main.js:93:43:93:43 | x | library input | main.js:94:20:94:32 | createHTML(x) | cross-site scripting |
|
||||
| main.js:99:28:99:28 | x | main.js:98:43:98:43 | x | main.js:99:28:99:28 | x | $@ which depends on $@ might later cause $@. | main.js:99:28:99:28 | x | Markdown rendering | main.js:98:43:98:43 | x | library input | main.js:100:24:100:26 | svg | cross-site scripting |
|
||||
| main.js:103:43:103:43 | x | main.js:98:43:98:43 | x | main.js:103:43:103:43 | x | $@ which depends on $@ might later cause $@. | main.js:103:43:103:43 | x | Markdown rendering | main.js:98:43:98:43 | x | library input | main.js:103:20:103:44 | myMerma ... id", x) | cross-site scripting |
|
||||
| main.js:105:26:105:26 | x | main.js:98:43:98:43 | x | main.js:105:26:105:26 | x | $@ which depends on $@ might later cause $@. | main.js:105:26:105:26 | x | Markdown rendering | main.js:98:43:98:43 | x | library input | main.js:106:24:106:26 | svg | cross-site scripting |
|
||||
| main.js:109:41:109:41 | x | main.js:98:43:98:43 | x | main.js:109:41:109:41 | x | $@ which depends on $@ might later cause $@. | main.js:109:41:109:41 | x | Markdown rendering | main.js:98:43:98:43 | x | library input | main.js:109:20:109:42 | mermaid ... id", x) | cross-site scripting |
|
||||
| main.js:111:37:111:37 | x | main.js:98:43:98:43 | x | main.js:111:37:111:37 | x | $@ which depends on $@ might later cause $@. | main.js:111:37:111:37 | x | Markdown rendering | main.js:98:43:98:43 | x | library input | main.js:112:24:112:26 | svg | cross-site scripting |
|
||||
| main.js:117:34:117:34 | s | main.js:116:47:116:47 | s | main.js:117:34:117:34 | s | $@ which depends on $@ might later cause $@. | main.js:117:34:117:34 | s | Markdown rendering | main.js:116:47:116:47 | s | library input | main.js:118:53:118:56 | html | cross-site scripting |
|
||||
| typed.ts:2:29:2:29 | s | typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s | $@ which depends on $@ might later cause $@. | typed.ts:2:29:2:29 | s | HTML construction | typed.ts:1:39:1:39 | s | library input | typed.ts:3:31:3:34 | html | cross-site scripting |
|
||||
| typed.ts:8:40:8:40 | s | typed.ts:6:43:6:43 | s | typed.ts:8:40:8:40 | s | $@ which depends on $@ might later cause $@. | typed.ts:8:40:8:40 | s | HTML construction | typed.ts:6:43:6:43 | s | library input | typed.ts:8:29:8:52 | "<span> ... /span>" | cross-site scripting |
|
||||
|
||||
@@ -92,4 +92,28 @@ function createHTML(x) {
|
||||
|
||||
module.exports.usesCreateHTML = function (x) {
|
||||
$("#foo").html(createHTML(x));
|
||||
}
|
||||
}
|
||||
|
||||
const myMermaid = require('mermaid');
|
||||
module.exports.usesCreateHTML = function (x) {
|
||||
myMermaid.render("id", x, function (svg) { // NOT OK
|
||||
$("#foo").html(svg);
|
||||
});
|
||||
|
||||
$("#foo").html(myMermaid.render("id", x)); // NOT OK
|
||||
|
||||
mermaid.render("id", x, function (svg) {// NOT OK
|
||||
$("#foo").html(svg);
|
||||
});
|
||||
|
||||
$("#foo").html(mermaid.render("id", x)); // NOT OK
|
||||
|
||||
mermaid.mermaidAPI.render("id", x, function (svg) {// NOT OK
|
||||
$("#foo").html(svg);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.xssThroughMarkdown = function (s) {
|
||||
const html = markdown.render(s); // NOT OK
|
||||
document.querySelector("#markdown").innerHTML = html;
|
||||
}
|
||||
|
||||
@@ -157,6 +157,18 @@ nodes
|
||||
| tst.js:26:26:26:40 | location.search |
|
||||
| tst.js:26:26:26:53 | locatio ... ring(1) |
|
||||
| tst.js:26:26:26:53 | locatio ... ring(1) |
|
||||
| tst.js:29:9:29:82 | source |
|
||||
| tst.js:29:18:29:41 | documen ... .search |
|
||||
| tst.js:29:18:29:41 | documen ... .search |
|
||||
| tst.js:29:18:29:82 | documen ... , "$1") |
|
||||
| tst.js:31:18:31:23 | source |
|
||||
| tst.js:31:18:31:23 | source |
|
||||
| tst.js:33:14:33:19 | source |
|
||||
| tst.js:33:14:33:19 | source |
|
||||
| tst.js:35:28:35:33 | source |
|
||||
| tst.js:35:28:35:33 | source |
|
||||
| tst.js:37:33:37:38 | source |
|
||||
| tst.js:37:33:37:38 | source |
|
||||
edges
|
||||
| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query |
|
||||
| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query |
|
||||
@@ -262,6 +274,17 @@ edges
|
||||
| tst.js:26:26:26:40 | location.search | tst.js:26:26:26:53 | locatio ... ring(1) |
|
||||
| tst.js:26:26:26:40 | location.search | tst.js:26:26:26:53 | locatio ... ring(1) |
|
||||
| tst.js:26:26:26:40 | location.search | tst.js:26:26:26:53 | locatio ... ring(1) |
|
||||
| tst.js:29:9:29:82 | source | tst.js:31:18:31:23 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:31:18:31:23 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:33:14:33:19 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:33:14:33:19 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:35:28:35:33 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:35:28:35:33 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:37:33:37:38 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:37:33:37:38 | source |
|
||||
| tst.js:29:18:29:41 | documen ... .search | tst.js:29:18:29:82 | documen ... , "$1") |
|
||||
| tst.js:29:18:29:41 | documen ... .search | tst.js:29:18:29:82 | documen ... , "$1") |
|
||||
| tst.js:29:18:29:82 | documen ... , "$1") | tst.js:29:9:29:82 | source |
|
||||
#select
|
||||
| NoSQLCodeInjection.js:18:24:18:37 | req.body.query | NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query | $@ flows to this location and is interpreted as code. | NoSQLCodeInjection.js:18:24:18:31 | req.body | User-provided value |
|
||||
| NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | NoSQLCodeInjection.js:19:36:19:43 | req.body | NoSQLCodeInjection.js:19:24:19:48 | "name = ... dy.name | $@ flows to this location and is interpreted as code. | NoSQLCodeInjection.js:19:36:19:43 | req.body | User-provided value |
|
||||
@@ -314,3 +337,7 @@ edges
|
||||
| tst.js:20:30:20:51 | documen ... on.hash | tst.js:20:30:20:51 | documen ... on.hash | tst.js:20:30:20:51 | documen ... on.hash | $@ flows to this location and is interpreted as code. | tst.js:20:30:20:51 | documen ... on.hash | User-provided value |
|
||||
| tst.js:23:6:23:46 | atob(do ... ing(1)) | tst.js:23:11:23:32 | documen ... on.hash | tst.js:23:6:23:46 | atob(do ... ing(1)) | $@ flows to this location and is interpreted as code. | tst.js:23:11:23:32 | documen ... on.hash | User-provided value |
|
||||
| tst.js:26:26:26:53 | locatio ... ring(1) | tst.js:26:26:26:40 | location.search | tst.js:26:26:26:53 | locatio ... ring(1) | $@ flows to this location and is interpreted as code. | tst.js:26:26:26:40 | location.search | User-provided value |
|
||||
| tst.js:31:18:31:23 | source | tst.js:29:18:29:41 | documen ... .search | tst.js:31:18:31:23 | source | $@ flows to this location and is interpreted as code. | tst.js:29:18:29:41 | documen ... .search | User-provided value |
|
||||
| tst.js:33:14:33:19 | source | tst.js:29:18:29:41 | documen ... .search | tst.js:33:14:33:19 | source | $@ flows to this location and is interpreted as code. | tst.js:29:18:29:41 | documen ... .search | User-provided value |
|
||||
| tst.js:35:28:35:33 | source | tst.js:29:18:29:41 | documen ... .search | tst.js:35:28:35:33 | source | $@ flows to this location and is interpreted as code. | tst.js:29:18:29:41 | documen ... .search | User-provided value |
|
||||
| tst.js:37:33:37:38 | source | tst.js:29:18:29:41 | documen ... .search | tst.js:37:33:37:38 | source | $@ flows to this location and is interpreted as code. | tst.js:29:18:29:41 | documen ... .search | User-provided value |
|
||||
|
||||
@@ -161,6 +161,18 @@ nodes
|
||||
| tst.js:26:26:26:40 | location.search |
|
||||
| tst.js:26:26:26:53 | locatio ... ring(1) |
|
||||
| tst.js:26:26:26:53 | locatio ... ring(1) |
|
||||
| tst.js:29:9:29:82 | source |
|
||||
| tst.js:29:18:29:41 | documen ... .search |
|
||||
| tst.js:29:18:29:41 | documen ... .search |
|
||||
| tst.js:29:18:29:82 | documen ... , "$1") |
|
||||
| tst.js:31:18:31:23 | source |
|
||||
| tst.js:31:18:31:23 | source |
|
||||
| tst.js:33:14:33:19 | source |
|
||||
| tst.js:33:14:33:19 | source |
|
||||
| tst.js:35:28:35:33 | source |
|
||||
| tst.js:35:28:35:33 | source |
|
||||
| tst.js:37:33:37:38 | source |
|
||||
| tst.js:37:33:37:38 | source |
|
||||
edges
|
||||
| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query |
|
||||
| NoSQLCodeInjection.js:18:24:18:31 | req.body | NoSQLCodeInjection.js:18:24:18:37 | req.body.query |
|
||||
@@ -270,5 +282,16 @@ edges
|
||||
| tst.js:26:26:26:40 | location.search | tst.js:26:26:26:53 | locatio ... ring(1) |
|
||||
| tst.js:26:26:26:40 | location.search | tst.js:26:26:26:53 | locatio ... ring(1) |
|
||||
| tst.js:26:26:26:40 | location.search | tst.js:26:26:26:53 | locatio ... ring(1) |
|
||||
| tst.js:29:9:29:82 | source | tst.js:31:18:31:23 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:31:18:31:23 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:33:14:33:19 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:33:14:33:19 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:35:28:35:33 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:35:28:35:33 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:37:33:37:38 | source |
|
||||
| tst.js:29:9:29:82 | source | tst.js:37:33:37:38 | source |
|
||||
| tst.js:29:18:29:41 | documen ... .search | tst.js:29:18:29:82 | documen ... , "$1") |
|
||||
| tst.js:29:18:29:41 | documen ... .search | tst.js:29:18:29:82 | documen ... , "$1") |
|
||||
| tst.js:29:18:29:82 | documen ... , "$1") | tst.js:29:9:29:82 | source |
|
||||
#select
|
||||
| eslint-escope-build.js:21:16:21:16 | c | eslint-escope-build.js:20:22:20:22 | c | eslint-escope-build.js:21:16:21:16 | c | $@ flows to here and is interpreted as code. | eslint-escope-build.js:20:22:20:22 | c | User-provided value |
|
||||
|
||||
@@ -24,3 +24,15 @@ eval(atob(document.location.hash.substring(1)));
|
||||
|
||||
// NOT OK
|
||||
$('<a>').attr("onclick", location.search.substring(1));
|
||||
|
||||
(function test() {
|
||||
var source = document.location.search.replace(/.*\bfoo\s*=\s*([^;]*).*/, "$1");
|
||||
|
||||
new Function(source); // NOT OK
|
||||
|
||||
Function(source); // NOT OK
|
||||
|
||||
new Function("a", "b", source); // NOT OK
|
||||
|
||||
new Function(...["a", "b"], source); // NOT OK
|
||||
})();
|
||||
@@ -16,10 +16,6 @@ nodes
|
||||
| tst.js:27:5:27:7 | foo |
|
||||
| tst.js:28:5:28:7 | foo |
|
||||
| tst.js:28:5:28:7 | foo |
|
||||
| tst.js:36:9:36:11 | foo |
|
||||
| tst.js:36:9:36:11 | foo |
|
||||
| tst.js:41:5:41:7 | foo |
|
||||
| tst.js:41:5:41:7 | foo |
|
||||
| tst.js:45:9:45:35 | foo |
|
||||
| tst.js:45:15:45:35 | ctx.req ... ery.foo |
|
||||
| tst.js:45:15:45:35 | ctx.req ... ery.foo |
|
||||
@@ -38,12 +34,14 @@ nodes
|
||||
| tst.js:92:9:92:16 | data.foo |
|
||||
| tst.js:92:9:92:16 | data.foo |
|
||||
| tst.js:92:9:92:16 | data.foo |
|
||||
| tst.js:95:9:95:16 | data.foo |
|
||||
| tst.js:95:9:95:16 | data.foo |
|
||||
| tst.js:95:9:95:16 | data.foo |
|
||||
| tst.js:98:9:98:16 | data.foo |
|
||||
| tst.js:98:9:98:16 | data.foo |
|
||||
| tst.js:98:9:98:16 | data.foo |
|
||||
| tst.js:103:9:103:29 | data |
|
||||
| tst.js:103:16:103:29 | req.query.data |
|
||||
| tst.js:103:16:103:29 | req.query.data |
|
||||
| tst.js:104:5:104:8 | data |
|
||||
| tst.js:104:5:104:8 | data |
|
||||
edges
|
||||
| tst.js:5:9:5:27 | foo | tst.js:6:5:6:7 | foo |
|
||||
| tst.js:5:9:5:27 | foo | tst.js:6:5:6:7 | foo |
|
||||
@@ -56,10 +54,6 @@ edges
|
||||
| tst.js:5:9:5:27 | foo | tst.js:27:5:27:7 | foo |
|
||||
| tst.js:5:9:5:27 | foo | tst.js:28:5:28:7 | foo |
|
||||
| tst.js:5:9:5:27 | foo | tst.js:28:5:28:7 | foo |
|
||||
| tst.js:5:9:5:27 | foo | tst.js:36:9:36:11 | foo |
|
||||
| tst.js:5:9:5:27 | foo | tst.js:36:9:36:11 | foo |
|
||||
| tst.js:5:9:5:27 | foo | tst.js:41:5:41:7 | foo |
|
||||
| tst.js:5:9:5:27 | foo | tst.js:41:5:41:7 | foo |
|
||||
| tst.js:5:15:5:27 | req.query.foo | tst.js:5:9:5:27 | foo |
|
||||
| tst.js:5:15:5:27 | req.query.foo | tst.js:5:9:5:27 | foo |
|
||||
| tst.js:14:16:14:18 | bar | tst.js:15:9:15:11 | bar |
|
||||
@@ -77,8 +71,11 @@ edges
|
||||
| tst.js:80:23:80:23 | p | tst.js:82:9:82:9 | p |
|
||||
| tst.js:90:5:90:12 | data.foo | tst.js:90:5:90:12 | data.foo |
|
||||
| tst.js:92:9:92:16 | data.foo | tst.js:92:9:92:16 | data.foo |
|
||||
| tst.js:95:9:95:16 | data.foo | tst.js:95:9:95:16 | data.foo |
|
||||
| tst.js:98:9:98:16 | data.foo | tst.js:98:9:98:16 | data.foo |
|
||||
| tst.js:103:9:103:29 | data | tst.js:104:5:104:8 | data |
|
||||
| tst.js:103:9:103:29 | data | tst.js:104:5:104:8 | data |
|
||||
| tst.js:103:16:103:29 | req.query.data | tst.js:103:9:103:29 | data |
|
||||
| tst.js:103:16:103:29 | req.query.data | tst.js:103:9:103:29 | data |
|
||||
#select
|
||||
| tst.js:6:5:6:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:6:5:6:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:8:5:8:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:8:5:8:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
@@ -86,12 +83,10 @@ edges
|
||||
| tst.js:15:9:15:11 | bar | tst.js:5:15:5:27 | req.query.foo | tst.js:15:9:15:11 | bar | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:27:5:27:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:27:5:27:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:28:5:28:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:28:5:28:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:36:9:36:11 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:36:9:36:11 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:41:5:41:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:41:5:41:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter |
|
||||
| tst.js:46:5:46:7 | foo | tst.js:45:15:45:35 | ctx.req ... ery.foo | tst.js:46:5:46:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:45:15:45:35 | ctx.req ... ery.foo | this HTTP request parameter |
|
||||
| tst.js:81:9:81:9 | p | tst.js:77:25:77:38 | req.query.path | tst.js:81:9:81:9 | p | Potential type confusion as $@ may be either an array or a string. | tst.js:77:25:77:38 | req.query.path | this HTTP request parameter |
|
||||
| tst.js:82:9:82:9 | p | tst.js:77:25:77:38 | req.query.path | tst.js:82:9:82:9 | p | Potential type confusion as $@ may be either an array or a string. | tst.js:77:25:77:38 | req.query.path | this HTTP request parameter |
|
||||
| tst.js:90:5:90:12 | data.foo | tst.js:90:5:90:12 | data.foo | tst.js:90:5:90:12 | data.foo | Potential type confusion as $@ may be either an array or a string. | tst.js:90:5:90:12 | data.foo | this HTTP request parameter |
|
||||
| tst.js:92:9:92:16 | data.foo | tst.js:92:9:92:16 | data.foo | tst.js:92:9:92:16 | data.foo | Potential type confusion as $@ may be either an array or a string. | tst.js:92:9:92:16 | data.foo | this HTTP request parameter |
|
||||
| tst.js:95:9:95:16 | data.foo | tst.js:95:9:95:16 | data.foo | tst.js:95:9:95:16 | data.foo | Potential type confusion as $@ may be either an array or a string. | tst.js:95:9:95:16 | data.foo | this HTTP request parameter |
|
||||
| tst.js:98:9:98:16 | data.foo | tst.js:98:9:98:16 | data.foo | tst.js:98:9:98:16 | data.foo | Potential type confusion as $@ may be either an array or a string. | tst.js:98:9:98:16 | data.foo | this HTTP request parameter |
|
||||
| tst.js:104:5:104:8 | data | tst.js:103:16:103:29 | req.query.data | tst.js:104:5:104:8 | data | Potential type confusion as $@ may be either an array or a string. | tst.js:103:16:103:29 | req.query.data | this HTTP request parameter |
|
||||
|
||||
@@ -100,7 +100,8 @@ express().get('/foo', function (req, res) {
|
||||
});
|
||||
|
||||
express().get('/foo', function (req, res) {
|
||||
let data = req.query;
|
||||
let data = req.query.data;
|
||||
data.indexOf(); // NOT OK
|
||||
if (Array.isArray(data)) {
|
||||
data.indexOf(); // OK
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user