Merge branch 'main' into js-insecure-http-parser

This commit is contained in:
Nate Johnson
2023-04-18 00:45:32 -04:00
895 changed files with 135227 additions and 114780 deletions

View File

@@ -1,9 +1,9 @@
{
"location": {
"endColumn": 4,
"endColumn": 5,
"endLine": 1,
"file": "bad.js",
"startColumn": 4,
"startColumn": 5,
"startLine": 1
},
"markdownMessage": "A parse error occurred: `Unexpected token`. Check the syntax of the file. If the file is invalid, correct the error or [exclude](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/customizing-code-scanning) the file from analysis.",

View File

@@ -1,3 +1,7 @@
## 0.5.2
No user-facing changes.
## 0.5.1
### Minor Analysis Improvements

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* `router.push` and `router.replace` in `Next.js` are now considered as XSS sink.

View File

@@ -0,0 +1,3 @@
## 0.5.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.5.1
lastReleaseVersion: 0.5.2

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-all
version: 0.5.2-dev
version: 0.6.0-dev
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript

View File

@@ -347,6 +347,46 @@ module API {
result = this.getASuccessor(Label::promisedError())
}
/**
* Gets a node representing a function that is a wrapper around the function represented by this node.
*
* Concretely, a function that forwards all its parameters to a call to `f` and returns the result of that call
* is considered a wrapper around `f`.
*
* Examples:
* ```js
* function f(x) {
* return g(x); // f = g.getForwardingFunction()
* }
*
* function doExec(x) {
* console.log(x);
* return exec(x); // doExec = exec.getForwardingFunction()
* }
*
* function doEither(x, y) {
* if (x > y) {
* return foo(x, y); // doEither = foo.getForwardingFunction()
* } else {
* return bar(x, y); // doEither = bar.getForwardingFunction()
* }
* }
*
* function wrapWithLogging(f) {
* return (x) => {
* console.log(x);
* return f(x); // f.getForwardingFunction() = anonymous arrow function
* }
* }
* wrapWithLogging(g); // g.getForwardingFunction() = wrapWithLogging(g)
* ```
*/
cached
Node getForwardingFunction() {
Stages::ApiStage::ref() and
result = this.getASuccessor(Label::forwardingFunction())
}
/**
* Gets any class that has this value as a decorator.
*
@@ -901,6 +941,9 @@ module API {
or
lbl = Label::return() and
ref = pred.getAnInvocation()
or
lbl = Label::forwardingFunction() and
DataFlow::functionForwardingStep(pred.getALocalUse(), ref)
)
or
exists(DataFlow::Node def, DataFlow::FunctionNode fn |
@@ -1431,6 +1474,9 @@ module API {
/** Gets the `return` edge label. */
LabelReturn return() { any() }
/** Gets the label representing a function wrapper that forwards to an underlying function. */
LabelForwardingFunction forwardingFunction() { any() }
/** Gets the `promised` edge label connecting a promise to its contained value. */
LabelPromised promised() { any() }
@@ -1483,6 +1529,7 @@ module API {
MkLabelDecoratedClass() or
MkLabelDecoratedMember() or
MkLabelDecoratedParameter() or
MkLabelForwardingFunction() or
MkLabelEntryPoint(API::EntryPoint e)
/** A label for an entry-point. */
@@ -1566,6 +1613,11 @@ module API {
override string toString() { result = "getReceiver()" }
}
/** A label for a function that is a wrapper around another function. */
class LabelForwardingFunction extends ApiLabel, MkLabelForwardingFunction {
override string toString() { result = "getForwardingFunction()" }
}
/** A label for a class decorated by the current value. */
class LabelDecoratedClass extends ApiLabel, MkLabelDecoratedClass {
override string toString() { result = "getADecoratedClass()" }

View File

@@ -157,10 +157,12 @@ private class FunctionalExtendCallShallow extends ExtendCall {
}
/**
* A taint propagating data flow edge from the objects flowing into an extend call to its return value
* A value-preserving data flow edge from the objects flowing into an extend call to its return value
* and to the source of the destination object.
*
* Since all object properties are preserved, we model this as a value-preserving step.
*/
private class ExtendCallTaintStep extends TaintTracking::SharedTaintStep {
private class ExtendCallStep extends PreCallGraphStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(ExtendCall extend |
pred = extend.getASourceOperand() and succ = extend.getDestinationOperand().getALocalSource()

View File

@@ -806,6 +806,10 @@ private predicate basicFlowStepNoBarrier(
callStep(pred, succ) and
summary = PathSummary::call()
or
// Implied receiver flow
CallGraph::impliedReceiverStep(pred, succ) and
summary = PathSummary::call()
or
// Flow out of function
returnStep(pred, succ) and
summary = PathSummary::return()

View File

@@ -241,22 +241,26 @@ module CallGraph {
)
}
private predicate shouldTrackObjectWithMethods(DataFlow::SourceNode node) {
private DataFlow::FunctionNode getAMethodOnPlainObject(DataFlow::SourceNode node) {
(
(
node instanceof DataFlow::ObjectLiteralNode
or
node instanceof DataFlow::FunctionNode
) and
node.getAPropertySource() instanceof DataFlow::FunctionNode
result = node.getAPropertySource()
or
exists(node.(DataFlow::ObjectLiteralNode).getPropertyGetter(_))
result = node.(DataFlow::ObjectLiteralNode).getPropertyGetter(_)
or
exists(node.(DataFlow::ObjectLiteralNode).getPropertySetter(_))
result = node.(DataFlow::ObjectLiteralNode).getPropertySetter(_)
) and
not node.getTopLevel().isExterns()
}
private predicate shouldTrackObjectWithMethods(DataFlow::SourceNode node) {
exists(getAMethodOnPlainObject(node))
}
/**
* Gets a step summary for tracking object literals.
*
@@ -273,4 +277,22 @@ module CallGraph {
or
StepSummary::step(getAnAllocationSiteRef(node), result, objectWithMethodsStep())
}
/**
* Holds if `pred` is assumed to flow to `succ` because a method is stored on an object that is assumed
* to be the receiver of calls to that method.
*
* For example, object literal below is assumed to flow to the receiver of the `foo` function:
* ```js
* let obj = {};
* obj.foo = function() {}
* ```
*/
cached
predicate impliedReceiverStep(DataFlow::SourceNode pred, DataFlow::SourceNode succ) {
exists(DataFlow::SourceNode host |
pred = getAnAllocationSiteRef(host) and
succ = getAMethodOnPlainObject(host).getReceiver()
)
}
}

View File

@@ -94,6 +94,10 @@ private module Cached {
DataFlow::localFieldStep(pred, succ) and
summary = LevelStep()
or
// Implied flow of host object into 'this' of a method
CallGraph::impliedReceiverStep(pred, succ) and
summary = CallStep()
or
exists(string prop |
basicStoreStep(pred, succ, prop) and
summary = StoreStep(prop)

View File

@@ -985,7 +985,9 @@ module Redux {
*/
private module ReactRedux {
/** Gets an API node referring to the `useSelector` function. */
API::Node useSelector() { result = API::moduleImport("react-redux").getMember("useSelector") }
API::Node useSelector() {
result = API::moduleImport("react-redux").getMember("useSelector").getForwardingFunction*()
}
/**
* A step out of a `useSelector` call, such as from `state.x` to the result of `useSelector(state => state.x)`.
@@ -994,7 +996,7 @@ module Redux {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(API::CallNode call |
call = useSelector().getACall() and
pred = call.getParameter(0).getReturn().asSink() and
pred = call.getCallback(0).getReturnNode() and
succ = call
)
}
@@ -1231,4 +1233,9 @@ module Redux {
}
}
}
/** For testing only. */
module Internal {
predicate getRootStateAccessPath = rootStateAccessPath/1;
}
}

View File

@@ -277,6 +277,7 @@ module Stages {
.getUnknownMember()
.getInstance()
.getReceiver()
.getForwardingFunction()
.getPromisedError()
.getADecoratedClass()
.getADecoratedMember()

View File

@@ -222,6 +222,8 @@ module ClientSideUrlRedirect {
HistoryWriteUrlSink() {
this = History::getBrowserHistory().getMember(["push", "replace"]).getACall().getArgument(0)
}
override predicate isXssSink() { any() }
}
/**
@@ -231,6 +233,8 @@ module ClientSideUrlRedirect {
NextRoutePushUrlSink() {
this = NextJS::nextRouter().getAMemberCall(["push", "replace"]).getArgument(0)
}
override predicate isXssSink() { any() }
}
private class SinkFromModel extends Sink {

View File

@@ -55,6 +55,22 @@ class Configuration extends TaintTracking::Configuration {
)
}
override predicate isSanitizerEdge(
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel lbl
) {
// Suppress the value-preserving step src -> dst in `extend(dst, src)`. This is modeled as a value-preserving
// step because it preserves all properties, but the destination is not actually Object.prototype.
exists(ExtendCall call |
pred = call.getASourceOperand() and
(
succ = call.getDestinationOperand().getALocalSource()
or
succ = call
) and
lbl instanceof ObjectPrototype
)
}
override predicate isAdditionalFlowStep(
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl
) {

View File

@@ -31,6 +31,13 @@ module UnsafeJQueryPlugin {
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* The receiver of a function, seen as a sanitizer.
*
* Plugins often do `$(this)` to coerce an existing DOM element to a jQuery object.
*/
private class ThisSanitizer extends Sanitizer instanceof DataFlow::ThisNode { }
/**
* An argument that may act as an HTML fragment rather than a CSS selector, as a sink for remote unsafe jQuery plugins.
*/

View File

@@ -1,3 +1,7 @@
## 0.5.6
No user-facing changes.
## 0.5.5
### Minor Analysis Improvements

View File

@@ -37,7 +37,7 @@
the hash of a password.
</p>
<sample src="examples/InsufficientPasswordHash_NodeJS.js"/>
<sample src="examples/InsufficientPasswordHash.js"/>
<p>
This is not secure, since the password can be efficiently
@@ -46,7 +46,7 @@
algorithm:
</p>
<sample src="examples/InsufficientPasswordHash_NodeJS_fixed.js"/>
<sample src="examples/InsufficientPasswordHash_fixed.js"/>
</example>
<references>

View File

@@ -1,8 +0,0 @@
const crypto = require('crypto-js')
function hashPassword(email, password) {
var algo = crypto.algo.SHA512.create()
algo.update(password, 'utf-8') // BAD
algo.update(email.toLowerCase(), 'utf-8')
var hash = algo.finalize()
return hash.toString(crypto.enc.Base64)
}

View File

@@ -1,8 +0,0 @@
const crypto = require('crypto-js')
function hashPassword(email, password) {
var algo = crypto.algo.PBKDF2.create()
algo.update(password, 'utf-8') // GOOD
algo.update(email.toLowerCase(), 'utf-8')
var hash = algo.finalize()
return hash.toString(crypto.enc.Base64)
}

View File

@@ -0,0 +1,5 @@
---
category: fix
---
* Fixed a bug where a destructuring pattern could not be parsed if it had a property
named `get` or `set` with a default value.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Improved the call graph to better handle the case where a function is stored on
a plain object and subsequently copied to a new host object via an `extend` call.

View File

@@ -0,0 +1,3 @@
## 0.5.6
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.5.5
lastReleaseVersion: 0.5.6

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-queries
version: 0.5.6-dev
version: 0.6.0-dev
groups:
- javascript
- queries

View File

@@ -0,0 +1,15 @@
import { useSelector } from 'react-redux';
function useSelectorWrapped(fn) {
return useSelector(fn);
}
function MyComponent(props) {
const x1 = useSelectorWrapped(state => state.x1);
const x2 = useSelectorWrapped(state => state.x2);
const x3 = useSelectorWrapped(state => state.x3);
const x4 = useSelectorWrapped(state => state.x4);
const x5 = useSelectorWrapped(state => state.x5);
return <span>X</span>;
}

View File

@@ -113,9 +113,11 @@ taintFlow
| react-redux.jsx:69:31:69:38 | source() | react-redux.jsx:76:10:76:36 | props.p ... Action3 |
| react-redux.jsx:70:30:70:37 | source() | react-redux.jsx:77:10:77:28 | props.propFromAsync |
reactComponentRef
| accessPaths.js:7:1:15:1 | functio ... pan>;\\n} | accessPaths.js:7:1:15:1 | functio ... pan>;\\n} |
| react-redux.jsx:64:1:80:1 | functio ... r}}/>\\n} | react-redux.jsx:64:1:80:1 | functio ... r}}/>\\n} |
| react-redux.jsx:64:1:80:1 | functio ... r}}/>\\n} | react-redux.jsx:94:28:94:84 | connect ... ponent) |
| react-redux.jsx:64:1:80:1 | functio ... r}}/>\\n} | react-redux.jsx:97:12:97:12 | c |
ambiguousAccessPath
getAffectedStateAccessPath
| react-redux.jsx:12:33:17:9 | (state, ... } | toolkit |
| react-redux.jsx:18:41:23:9 | (state, ... } | toolkit |
@@ -163,3 +165,24 @@ reducerToStateStep
| react-redux.jsx:35:45:35:58 | action.payload | react-redux.jsx:86:31:86:54 | state.m ... alValue |
| react-redux.jsx:39:42:39:55 | action.payload | react-redux.jsx:87:32:87:56 | state.m ... lValue2 |
| react-redux.jsx:44:27:46:14 | [1, 2, ... }) | react-redux.jsx:88:32:88:56 | state.m ... lValue3 |
getRootStateAccessPath
| manual | react-redux.jsx:86:31:86:42 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("manual") |
| manual | react-redux.jsx:87:32:87:43 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("manual") |
| manual | react-redux.jsx:88:32:88:43 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("manual") |
| manual.manualValue | react-redux.jsx:86:31:86:54 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("manual").getMember("manualValue") |
| manual.manualValue2 | react-redux.jsx:87:32:87:56 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("manual").getMember("manualValue2") |
| manual.manualValue3 | react-redux.jsx:88:32:88:56 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("manual").getMember("manualValue3") |
| toolkit | react-redux.jsx:84:32:84:44 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("toolkit") |
| toolkit | react-redux.jsx:85:24:85:36 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("toolkit") |
| toolkit.asyncValue | react-redux.jsx:85:24:85:47 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("toolkit").getMember("asyncValue") |
| toolkit.value | react-redux.jsx:84:32:84:50 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("toolkit").getMember("value") |
| x1 | accessPaths.js:8:16:8:52 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getForwardingFunction().getReturn() |
| x1 | accessPaths.js:8:44:8:51 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getParameter(0).getParameter(0).getMember("x1") |
| x2 | accessPaths.js:9:16:9:52 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getForwardingFunction().getReturn() |
| x2 | accessPaths.js:9:44:9:51 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getParameter(0).getParameter(0).getMember("x2") |
| x3 | accessPaths.js:10:16:10:52 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getForwardingFunction().getReturn() |
| x3 | accessPaths.js:10:44:10:51 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getParameter(0).getParameter(0).getMember("x3") |
| x4 | accessPaths.js:11:16:11:52 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getForwardingFunction().getReturn() |
| x4 | accessPaths.js:11:44:11:51 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getParameter(0).getParameter(0).getMember("x4") |
| x5 | accessPaths.js:12:16:12:52 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getForwardingFunction().getReturn() |
| x5 | accessPaths.js:12:44:12:51 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getParameter(0).getParameter(0).getMember("x5") |

View File

@@ -63,3 +63,10 @@ query predicate taintFlow(DataFlow::Node source, DataFlow::Node sink) {
query DataFlow::SourceNode reactComponentRef(ReactComponent component) {
result = component.getAComponentCreatorReference()
}
query predicate ambiguousAccessPath(API::Node node, string path) {
count(string accessPath | Redux::Internal::getRootStateAccessPath(accessPath) = node) > 1 and
Redux::Internal::getRootStateAccessPath(path) = node
}
query predicate getRootStateAccessPath = Redux::Internal::getRootStateAccessPath/1;

View File

@@ -36,6 +36,8 @@ nodes
| tst-UntrustedDataToExternalAPI.js:33:14:33:22 | untrusted |
| tst-UntrustedDataToExternalAPI.js:34:34:34:42 | untrusted |
| tst-UntrustedDataToExternalAPI.js:34:34:34:42 | untrusted |
| tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} |
| tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} |
| tst-UntrustedDataToExternalAPI.js:42:8:42:16 | untrusted |
@@ -83,6 +85,8 @@ edges
| tst-UntrustedDataToExternalAPI.js:24:21:24:41 | JSON.pa ... rusted) | tst-UntrustedDataToExternalAPI.js:24:20:24:42 | [JSON.p ... usted)] |
| tst-UntrustedDataToExternalAPI.js:24:21:24:41 | JSON.pa ... rusted) | tst-UntrustedDataToExternalAPI.js:24:20:24:42 | [JSON.p ... usted)] |
| tst-UntrustedDataToExternalAPI.js:24:32:24:40 | untrusted | tst-UntrustedDataToExternalAPI.js:24:21:24:41 | JSON.pa ... rusted) |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} |
| tst-UntrustedDataToExternalAPI.js:42:8:42:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} |
| tst-UntrustedDataToExternalAPI.js:42:8:42:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} |
| tst-UntrustedDataToExternalAPI.js:43:8:43:16 | untrusted | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} |
@@ -101,4 +105,5 @@ edges
| tst-UntrustedDataToExternalAPI.js:30:13:30:30 | getDeepUntrusted() | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | tst-UntrustedDataToExternalAPI.js:30:13:30:30 | getDeepUntrusted() | Call to external-lib() [param 0] with untrusted data from $@. | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | window.name |
| tst-UntrustedDataToExternalAPI.js:33:14:33:22 | untrusted | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | tst-UntrustedDataToExternalAPI.js:33:14:33:22 | untrusted | Call to external-lib.get.[callback].[param 'res'].send() [param 0] with untrusted data from $@. | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | window.name |
| tst-UntrustedDataToExternalAPI.js:34:34:34:42 | untrusted | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | tst-UntrustedDataToExternalAPI.js:34:34:34:42 | untrusted | Call to external-lib.get.[callback].[param 'req'].app.locals.something.foo() [param 0] with untrusted data from $@. | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | window.name |
| tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | tst-UntrustedDataToExternalAPI.js:41:7:41:8 | {} | Call to lodash.merge() [param 0] with untrusted data from $@. | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | window.name |
| tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | tst-UntrustedDataToExternalAPI.js:41:11:45:1 | {\\n x ... usted\\n} | Call to lodash.merge() [param 1] with untrusted data from $@. | tst-UntrustedDataToExternalAPI.js:3:17:3:27 | window.name | window.name |

View File

@@ -560,6 +560,25 @@ nodes
| react-use-context.js:16:26:16:36 | window.name |
| react-use-context.js:16:26:16:36 | window.name |
| react-use-context.js:16:26:16:36 | window.name |
| react-use-router.js:4:9:4:28 | router |
| react-use-router.js:4:18:4:28 | useRouter() |
| react-use-router.js:8:21:8:26 | router |
| react-use-router.js:8:21:8:32 | router.query |
| react-use-router.js:8:21:8:32 | router.query |
| react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:11:24:11:29 | router |
| react-use-router.js:11:24:11:35 | router.query |
| react-use-router.js:11:24:11:35 | router.query |
| react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:22:15:22:24 | router |
| react-use-router.js:22:17:22:22 | router |
| react-use-router.js:23:43:23:48 | router |
| react-use-router.js:23:43:23:54 | router.query |
| react-use-router.js:23:43:23:54 | router.query |
| react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-state.js:4:9:4:49 | state |
| react-use-state.js:4:9:4:49 | state |
| react-use-state.js:4:10:4:14 | state |
@@ -1096,6 +1115,14 @@ nodes
| tst.js:491:23:491:35 | location.hash |
| tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:494:18:494:30 | location.hash |
| tst.js:494:18:494:30 | location.hash |
| tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:501:33:501:63 | decodeU ... n.hash) |
| tst.js:501:33:501:63 | decodeU ... n.hash) |
| tst.js:501:43:501:62 | window.location.hash |
| tst.js:501:43:501:62 | window.location.hash |
| typeahead.js:20:13:20:45 | target |
| typeahead.js:20:22:20:45 | documen ... .search |
| typeahead.js:20:22:20:45 | documen ... .search |
@@ -1700,6 +1727,28 @@ edges
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
| react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name |
| react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name |
| react-use-router.js:4:9:4:28 | router | react-use-router.js:8:21:8:26 | router |
| react-use-router.js:4:9:4:28 | router | react-use-router.js:11:24:11:29 | router |
| react-use-router.js:4:18:4:28 | useRouter() | react-use-router.js:4:9:4:28 | router |
| react-use-router.js:8:21:8:26 | router | react-use-router.js:8:21:8:32 | router.query |
| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:8:21:8:39 | router.query.foobar | react-use-router.js:4:18:4:28 | useRouter() |
| react-use-router.js:11:24:11:29 | router | react-use-router.js:11:24:11:35 | router.query |
| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:22:15:22:24 | router | react-use-router.js:23:43:23:48 | router |
| react-use-router.js:22:17:22:22 | router | react-use-router.js:22:15:22:24 | router |
| react-use-router.js:23:43:23:48 | router | react-use-router.js:23:43:23:54 | router.query |
| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:22:17:22:22 | router |
| react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state |
| react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state |
| react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state |
@@ -2222,6 +2271,14 @@ edges
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) |
| tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) |
| tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) |
| tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) |
| typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target |
| typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:20:13:20:45 | target |
| typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:20:13:20:45 | target |
@@ -2386,6 +2443,10 @@ edges
| react-native.js:9:27:9:33 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
| react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name | Cross-site scripting vulnerability due to $@. | react-use-context.js:10:22:10:32 | window.name | user-provided value |
| react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name | Cross-site scripting vulnerability due to $@. | react-use-context.js:16:26:16:36 | window.name | user-provided value |
| react-use-router.js:8:21:8:39 | router.query.foobar | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:8:21:8:32 | router.query | user-provided value |
| react-use-router.js:11:24:11:42 | router.query.foobar | react-use-router.js:8:21:8:32 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:8:21:8:32 | router.query | user-provided value |
| react-use-router.js:11:24:11:42 | router.query.foobar | react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:11:24:11:35 | router.query | user-provided value |
| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar | Cross-site scripting vulnerability due to $@. | react-use-router.js:23:43:23:54 | router.query | user-provided value |
| react-use-state.js:5:51:5:55 | state | react-use-state.js:4:38:4:48 | window.name | react-use-state.js:5:51:5:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:4:38:4:48 | window.name | user-provided value |
| react-use-state.js:11:51:11:55 | state | react-use-state.js:10:14:10:24 | window.name | react-use-state.js:11:51:11:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:10:14:10:24 | window.name | user-provided value |
| react-use-state.js:17:51:17:55 | state | react-use-state.js:16:20:16:30 | window.name | react-use-state.js:17:51:17:55 | state | Cross-site scripting vulnerability due to $@. | react-use-state.js:16:20:16:30 | window.name | user-provided value |
@@ -2505,6 +2566,8 @@ edges
| tst.js:476:20:476:22 | url | tst.js:471:13:471:36 | documen ... .search | tst.js:476:20:476:22 | url | Cross-site scripting vulnerability due to $@. | tst.js:471:13:471:36 | documen ... .search | user-provided value |
| tst.js:486:22:486:24 | url | tst.js:471:13:471:36 | documen ... .search | tst.js:486:22:486:24 | url | Cross-site scripting vulnerability due to $@. | tst.js:471:13:471:36 | documen ... .search | user-provided value |
| tst.js:491:23:491:45 | locatio ... bstr(1) | tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) | Cross-site scripting vulnerability due to $@. | tst.js:491:23:491:35 | location.hash | user-provided value |
| tst.js:494:18:494:40 | locatio ... bstr(1) | tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) | Cross-site scripting vulnerability due to $@. | tst.js:494:18:494:30 | location.hash | user-provided value |
| tst.js:501:33:501:63 | decodeU ... n.hash) | tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | Cross-site scripting vulnerability due to $@. | tst.js:501:43:501:62 | window.location.hash | user-provided value |
| typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:45 | documen ... .search | user-provided value |
| v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value |
| various-concat-obfuscations.js:4:4:4:31 | "<div>" ... </div>" | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | various-concat-obfuscations.js:4:4:4:31 | "<div>" ... </div>" | Cross-site scripting vulnerability due to $@. | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | user-provided value |

View File

@@ -572,6 +572,25 @@ nodes
| react-use-context.js:16:26:16:36 | window.name |
| react-use-context.js:16:26:16:36 | window.name |
| react-use-context.js:16:26:16:36 | window.name |
| react-use-router.js:4:9:4:28 | router |
| react-use-router.js:4:18:4:28 | useRouter() |
| react-use-router.js:8:21:8:26 | router |
| react-use-router.js:8:21:8:32 | router.query |
| react-use-router.js:8:21:8:32 | router.query |
| react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:11:24:11:29 | router |
| react-use-router.js:11:24:11:35 | router.query |
| react-use-router.js:11:24:11:35 | router.query |
| react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:22:15:22:24 | router |
| react-use-router.js:22:17:22:22 | router |
| react-use-router.js:23:43:23:48 | router |
| react-use-router.js:23:43:23:54 | router.query |
| react-use-router.js:23:43:23:54 | router.query |
| react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-state.js:4:9:4:49 | state |
| react-use-state.js:4:9:4:49 | state |
| react-use-state.js:4:10:4:14 | state |
@@ -1108,6 +1127,14 @@ nodes
| tst.js:491:23:491:35 | location.hash |
| tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:494:18:494:30 | location.hash |
| tst.js:494:18:494:30 | location.hash |
| tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:501:33:501:63 | decodeU ... n.hash) |
| tst.js:501:33:501:63 | decodeU ... n.hash) |
| tst.js:501:43:501:62 | window.location.hash |
| tst.js:501:43:501:62 | window.location.hash |
| typeahead.js:9:28:9:30 | loc |
| typeahead.js:9:28:9:30 | loc |
| typeahead.js:9:28:9:30 | loc |
@@ -1762,6 +1789,28 @@ edges
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
| react-use-context.js:10:22:10:32 | window.name | react-use-context.js:10:22:10:32 | window.name |
| react-use-context.js:16:26:16:36 | window.name | react-use-context.js:16:26:16:36 | window.name |
| react-use-router.js:4:9:4:28 | router | react-use-router.js:8:21:8:26 | router |
| react-use-router.js:4:9:4:28 | router | react-use-router.js:11:24:11:29 | router |
| react-use-router.js:4:18:4:28 | useRouter() | react-use-router.js:4:9:4:28 | router |
| react-use-router.js:8:21:8:26 | router | react-use-router.js:8:21:8:32 | router.query |
| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:8:21:8:32 | router.query | react-use-router.js:8:21:8:39 | router.query.foobar |
| react-use-router.js:8:21:8:39 | router.query.foobar | react-use-router.js:4:18:4:28 | useRouter() |
| react-use-router.js:11:24:11:29 | router | react-use-router.js:11:24:11:35 | router.query |
| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:11:24:11:35 | router.query | react-use-router.js:11:24:11:42 | router.query.foobar |
| react-use-router.js:22:15:22:24 | router | react-use-router.js:23:43:23:48 | router |
| react-use-router.js:22:17:22:22 | router | react-use-router.js:22:15:22:24 | router |
| react-use-router.js:23:43:23:48 | router | react-use-router.js:23:43:23:54 | router.query |
| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-router.js:23:43:23:54 | router.query | react-use-router.js:23:43:23:61 | router.query.foobar |
| react-use-router.js:23:43:23:61 | router.query.foobar | react-use-router.js:22:17:22:22 | router |
| react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state |
| react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state |
| react-use-state.js:4:9:4:49 | state | react-use-state.js:5:51:5:55 | state |
@@ -2284,6 +2333,14 @@ edges
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) |
| tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) |
| tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) |
| tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) |
| tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) |
| typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc |
| typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc |
| typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc |

View File

@@ -0,0 +1,25 @@
import { useRouter } from 'next/router'
export function nextRouter() {
const router = useRouter();
return (
<div>
<span onClick={() => {
router.push(router.query.foobar) // NOT OK
}}>Click to XSS 1</span>
<span onClick={() => {
router.replace(router.query.foobar) // NOT OK
}}>Click to XSS 2</span>
<span onClick={() => {
router.push('/?foobar=' + router.query.foobar) // OK
}}>Safe Link</span>
</div>
)
}
import { withRouter } from 'next/router'
function Page({ router }) {
return <span onClick={() => router.push(router.query.foobar)}>Click to XSS 3</span> // NOT OK
}
export const pageWithRouter = withRouter(Page);

View File

@@ -313,7 +313,7 @@ function basicExceptions() {
}
function handlebarsSafeString() {
return new Handlebars.SafeString(location); // NOT OK!
return new Handlebars.SafeString(location); // NOT OK!
}
function test2() {
@@ -355,15 +355,15 @@ function thisNodes() {
var target = document.location.search
this.html(target); // NOT OK. (this is a jQuery object)
this.innerHTML = target // OK. (this is a jQuery object)
this.each(function (i, e) {
this.innerHTML = target; // NOT OK. (this is a DOM-node);
this.html(target); // OK. (this is a DOM-node);
e.innerHTML = target; // NOT OK.
});
}
$.fn[pluginName] = myPlugin;
$.fn[pluginName] = myPlugin;
}
@@ -380,7 +380,7 @@ function test() {
function test() {
var target = document.location.search
$('myId').html(target); // NOT OK
$('myId').html(target.taint); // NOT OK
@@ -401,7 +401,7 @@ function test() {
if (random()) {return;}
$('myId').html(target.taint6); // OK
if (random()) {target.taint7 = "safe";}
$('myId').html(target.taint7); // NOT OK
@@ -489,4 +489,17 @@ function urlStuff() {
window.open(location.hash.substr(1)); // OK - any JavaScript is executed in another context
navigation.navigate(location.hash.substr(1)); // NOT OK
const myHistory = require('history').createBrowserHistory();
myHistory.push(location.hash.substr(1)); // NOT OK
}
function Foo() {
this.foo = document;
var obj = {
bar: function() {
this.foo.body.innerHTML = decodeURI(window.location.hash); // NOT OK
}
};
Object.assign(this, obj);
}

View File

@@ -188,8 +188,18 @@
}
// extending options
options = $.extend( {}, options );
var target = $( options.of ); // NOT OK
console.log(target);
};
$.fn.blockReceiver = function( options ) {
$.extend({
foo() {
$(this); // OK
}
},
options,
);
};
});

View File

@@ -103,11 +103,23 @@ app.get('/bar', (req, res) => {
let object = {};
object[taint][taint] = taint; // NOT OK
const bad = ["__proto__", "constructor"];
if (bad.includes(taint)) {
return;
}
object[taint][taint] = taint; // OK
});
});
app.get('/assign', (req, res) => {
let taint = String(req.query.data);
let plainObj = {};
let object = Object.assign({}, plainObj[taint]);
object[taint] = taint; // OK - 'object' is not Object.prototype itself (but possibly a copy)
let dest = {};
Object.assign(dest, plainObj[taint]);
dest[taint] = taint; // OK - 'dest' is not Object.prototype itself (but possibly a copy)
});