mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
JS: Add model of react hooks and react-router
This commit is contained in:
@@ -307,7 +307,8 @@ module SourceNode {
|
|||||||
astNode instanceof FunctionBindExpr or
|
astNode instanceof FunctionBindExpr or
|
||||||
astNode instanceof DynamicImportExpr or
|
astNode instanceof DynamicImportExpr or
|
||||||
astNode instanceof ImportSpecifier or
|
astNode instanceof ImportSpecifier or
|
||||||
astNode instanceof ImportMetaExpr
|
astNode instanceof ImportMetaExpr or
|
||||||
|
astNode instanceof TaggedTemplateExpr
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
DataFlow::parameterNode(this, _)
|
DataFlow::parameterNode(this, _)
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ module TaintTracking {
|
|||||||
* taint to flow from `v` to any read of `c2.state.p`, where `c2`
|
* taint to flow from `v` to any read of `c2.state.p`, where `c2`
|
||||||
* also is an instance of `C`.
|
* also is an instance of `C`.
|
||||||
*/
|
*/
|
||||||
private class ReactComponentStateTaintStep extends AdditionalTaintStep, DataFlow::ValueNode {
|
private class ReactComponentStateTaintStep extends AdditionalTaintStep {
|
||||||
DataFlow::Node source;
|
DataFlow::Node source;
|
||||||
|
|
||||||
ReactComponentStateTaintStep() {
|
ReactComponentStateTaintStep() {
|
||||||
@@ -358,7 +358,7 @@ module TaintTracking {
|
|||||||
* taint to flow from `v` to any read of `c2.props.p`, where `c2`
|
* taint to flow from `v` to any read of `c2.props.p`, where `c2`
|
||||||
* also is an instance of `C`.
|
* also is an instance of `C`.
|
||||||
*/
|
*/
|
||||||
private class ReactComponentPropsTaintStep extends AdditionalTaintStep, DataFlow::ValueNode {
|
private class ReactComponentPropsTaintStep extends AdditionalTaintStep {
|
||||||
DataFlow::Node source;
|
DataFlow::Node source;
|
||||||
|
|
||||||
ReactComponentPropsTaintStep() {
|
ReactComponentPropsTaintStep() {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
|
||||||
|
private import semmle.javascript.dataflow.internal.PreCallGraphStep
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a reference to the 'React' object.
|
* Gets a reference to the 'React' object.
|
||||||
@@ -548,3 +550,228 @@ private class ReactJSXElement extends JSXElement {
|
|||||||
*/
|
*/
|
||||||
ReactComponent getComponent() { result = component }
|
ReactComponent getComponent() { result = component }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Step through the state variable of a `useState` call.
|
||||||
|
*
|
||||||
|
* It returns a pair of the current state, and a callback to change the state.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
* ```js
|
||||||
|
* let [state, setState] = useState(initialValue);
|
||||||
|
* let [state, setState] = useState(() => initialValue); // lazy initial state
|
||||||
|
*
|
||||||
|
* setState(newState);
|
||||||
|
* setState(prevState => { ... });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
private class UseStateStep extends PreCallGraphStep {
|
||||||
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
|
exists(DataFlow::CallNode call | call = react().getAMemberCall("useState") |
|
||||||
|
pred =
|
||||||
|
[call.getArgument(0), // initial state
|
||||||
|
call.getCallback(0).getReturnNode(), // lazy initial state
|
||||||
|
call.getAPropertyRead("1").getACall().getArgument(0), // setState invocation
|
||||||
|
call.getAPropertyRead("1").getACall().getCallback(0).getReturnNode()] and // setState with callback
|
||||||
|
succ = call.getAPropertyRead("0")
|
||||||
|
or
|
||||||
|
// Propagate current state into the callback argument of `setState(prevState => { ... })`
|
||||||
|
pred = call.getAPropertyRead("0") and
|
||||||
|
succ = call.getAPropertyRead("1").getACall().getCallback(0).getParameter(0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A step through a React context object.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
* ```js
|
||||||
|
* let MyContext = React.createContext('foo');
|
||||||
|
*
|
||||||
|
* <MyContext.Provider value={pred}>
|
||||||
|
* <Foo/>
|
||||||
|
* </MyContext.Provider>
|
||||||
|
*
|
||||||
|
* function Foo() {
|
||||||
|
* let succ = useContext(MyContext);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
private class UseContextStep extends PreCallGraphStep {
|
||||||
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
|
exists(DataFlow::CallNode context |
|
||||||
|
pred = getAContextInput(context) and
|
||||||
|
succ = getAContextOutput(context)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a data flow node referring to the result of the given `createContext` call.
|
||||||
|
*/
|
||||||
|
private DataFlow::SourceNode getAContextRef(DataFlow::CallNode createContext) {
|
||||||
|
createContext = react().getAMemberCall("createContext") and
|
||||||
|
result = createContext
|
||||||
|
or
|
||||||
|
// Track through imports/exports, but not full type tracking, so this can be used as a PreCallGraphStep.
|
||||||
|
exists(DataFlow::Node mid |
|
||||||
|
getAContextRef(createContext).flowsTo(mid) and
|
||||||
|
FlowSteps::propertyFlowStep(mid, result)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a data flow node whose value is provided to the given context object.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
* ```jsx
|
||||||
|
* React.createContext(x);
|
||||||
|
* <MyContext.Provider value={x}>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlow::Node getAContextInput(DataFlow::CallNode createContext) {
|
||||||
|
result = createContext.getArgument(0) // initial value
|
||||||
|
or
|
||||||
|
exists(JSXElement provider |
|
||||||
|
getAContextRef(createContext)
|
||||||
|
.getAPropertyRead("Provider")
|
||||||
|
.flowsTo(provider.getNameExpr().flow()) and
|
||||||
|
result = provider.getAttributeByName("value").getValue().flow()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a data flow node whose value is obtained from the given context object.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
* ```js
|
||||||
|
* let value = useContext(MyContext);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlow::CallNode getAContextOutput(DataFlow::CallNode createContext) {
|
||||||
|
result = react().getAMemberCall("useContext") and
|
||||||
|
getAContextRef(createContext).flowsTo(result.getArgument(0))
|
||||||
|
or
|
||||||
|
exists(DataFlow::ClassNode cls |
|
||||||
|
getAContextRef(createContext).flowsTo(cls.getAPropertyWrite("contextType").getRhs()) and
|
||||||
|
result = cls.getAReceiverNode().getAPropertyRead("context")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A step through a `useMemo` call; for example:
|
||||||
|
* ```js
|
||||||
|
* let succ = useMemo(() => pred, []);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
private class UseMemoStep extends PreCallGraphStep {
|
||||||
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
|
exists(DataFlow::CallNode call |
|
||||||
|
call = react().getAMemberCall("useMemo")
|
||||||
|
|
|
||||||
|
pred = call.getCallback(0).getReturnNode() and
|
||||||
|
succ = call
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataFlow::SourceNode reactRouterDom() {
|
||||||
|
result = DataFlow::moduleImport("react-router-dom")
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReactRouterSource extends RemoteFlowSource {
|
||||||
|
ReactRouterSource() {
|
||||||
|
this = reactRouterDom().getAMemberCall("useParams")
|
||||||
|
or
|
||||||
|
this = reactRouterDom().getAMemberCall("useRouteMatch").getAPropertyRead(["params", "url"])
|
||||||
|
}
|
||||||
|
|
||||||
|
override string getSourceType() {
|
||||||
|
result = "react-router path parameters"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `mod` transitively depends on `react-router-dom`.
|
||||||
|
*
|
||||||
|
* We assume any React component in such a file may be used in a context where react-router
|
||||||
|
* injects the `location` property in its `props` object.
|
||||||
|
*/
|
||||||
|
private predicate dependsOnReactRouter(Module mod) {
|
||||||
|
mod.getAnImport().getImportedPath().getValue() = "react-router-dom"
|
||||||
|
or
|
||||||
|
dependsOnReactRouter(mod.getAnImportedModule())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to the DOM location obtained through `react-router-dom`
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
* ```js
|
||||||
|
* let location = useLocation();
|
||||||
|
*
|
||||||
|
* function MyComponent(props) {
|
||||||
|
* props.location;
|
||||||
|
* }
|
||||||
|
* export default withRouter(MyComponent);
|
||||||
|
*/
|
||||||
|
private class ReactRouterLocationSource extends DOM::LocationSource::Range {
|
||||||
|
ReactRouterLocationSource() {
|
||||||
|
this = reactRouterDom().getAMemberCall("useLocation")
|
||||||
|
or
|
||||||
|
exists(ReactComponent component |
|
||||||
|
dependsOnReactRouter(component.getTopLevel()) and
|
||||||
|
this = component.getAPropRead("location")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a reference to a function which, if called with a React component, returns wrapped
|
||||||
|
* version of that component, which we model as a direct reference to the underlying component.
|
||||||
|
*/
|
||||||
|
private DataFlow::SourceNode higherOrderComponentBuilder() {
|
||||||
|
result = react().getAPropertyRead("memo")
|
||||||
|
or
|
||||||
|
result = DataFlow::moduleMember("react-redux", "connect").getACall()
|
||||||
|
or
|
||||||
|
result = reactRouterDom().getAPropertyRead("withRouter")
|
||||||
|
or
|
||||||
|
exists(FunctionCompositionCall compose |
|
||||||
|
higherOrderComponentBuilder().flowsTo(compose.getAnOperandNode()) and
|
||||||
|
result = compose
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class HigherOrderComponentStep extends PreCallGraphStep {
|
||||||
|
override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||||
|
// `lazy(() => P)` returns a proxy for the component eventually returned by
|
||||||
|
// the promise P. We model this call as simply returning the value in P.
|
||||||
|
// It is primarily used for lazy-loading of React components.
|
||||||
|
exists(DataFlow::CallNode call |
|
||||||
|
call = react().getAMemberCall("lazy") and
|
||||||
|
pred = call.getCallback(0).getReturnNode() and
|
||||||
|
succ = call and
|
||||||
|
prop = Promises::valueProp()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
|
// `memo(f)` returns a function behaves as `f` but caches results
|
||||||
|
// It is sometimes used to wrap an entire functional component.
|
||||||
|
exists(DataFlow::CallNode call |
|
||||||
|
call = higherOrderComponentBuilder().getACall() and
|
||||||
|
pred = call.getArgument(0) and
|
||||||
|
succ = call
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(TaggedTemplateExpr expr, DataFlow::CallNode call |
|
||||||
|
call = DataFlow::moduleImport("styled-components").getACall() and
|
||||||
|
pred = call.getArgument(0) and
|
||||||
|
call.flowsTo(expr.getTag().flow()) and
|
||||||
|
succ = expr.flow()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { compose } from 'redux';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import unknownFunction from 'somewhere';
|
||||||
|
|
||||||
|
import { MyComponent } from './exportedComponent';
|
||||||
|
|
||||||
|
const StyledComponent = styled(MyComponent)`
|
||||||
|
color: red;
|
||||||
|
`;
|
||||||
|
|
||||||
|
function mapStateToProps(x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
function mapDispatchToProps(x) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
const withConnect = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
||||||
|
const ConnectedComponent = compose(withConnect, unknownFunction)(StyledComponent);
|
||||||
|
|
||||||
|
export default memo(ConnectedComponent);
|
||||||
@@ -227,6 +227,9 @@ test_ReactComponent_getACandidatePropsValue
|
|||||||
| props.js:30:46:30:67 | "propFr ... tProps" |
|
| props.js:30:46:30:67 | "propFr ... tProps" |
|
||||||
| props.js:32:22:32:34 | "propFromJSX" |
|
| props.js:32:22:32:34 | "propFromJSX" |
|
||||||
| props.js:34:33:34:53 | "propFr ... ructor" |
|
| props.js:34:33:34:53 | "propFr ... ructor" |
|
||||||
|
| useHigherOrderComponent.jsx:5:33:5:37 | "red" |
|
||||||
|
| useHigherOrderComponent.jsx:11:39:11:44 | "lazy" |
|
||||||
|
| useHigherOrderComponent.jsx:17:40:17:46 | "lazy2" |
|
||||||
test_ReactComponent
|
test_ReactComponent
|
||||||
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} |
|
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} |
|
||||||
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} |
|
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} |
|
||||||
@@ -285,6 +288,9 @@ test_JSXname
|
|||||||
| thisAccesses.js:60:19:60:41 | <this.n ... s.name> | thisAccesses.js:60:20:60:28 | this.name | this.name | dot |
|
| thisAccesses.js:60:19:60:41 | <this.n ... s.name> | thisAccesses.js:60:20:60:28 | this.name | this.name | dot |
|
||||||
| thisAccesses.js:61:19:61:41 | <this.t ... s.this> | thisAccesses.js:61:20:61:28 | this.this | this.this | dot |
|
| thisAccesses.js:61:19:61:41 | <this.t ... s.this> | thisAccesses.js:61:20:61:28 | this.this | this.this | dot |
|
||||||
| thisAccesses_importedMappers.js:13:16:13:21 | <div/> | thisAccesses_importedMappers.js:13:17:13:19 | div | div | Identifier |
|
| thisAccesses_importedMappers.js:13:16:13:21 | <div/> | thisAccesses_importedMappers.js:13:17:13:19 | div | div | Identifier |
|
||||||
|
| useHigherOrderComponent.jsx:5:12:5:39 | <SomeCo ... "red"/> | useHigherOrderComponent.jsx:5:13:5:25 | SomeComponent | SomeComponent | Identifier |
|
||||||
|
| useHigherOrderComponent.jsx:11:12:11:46 | <LazyLo ... lazy"/> | useHigherOrderComponent.jsx:11:13:11:31 | LazyLoadedComponent | LazyLoadedComponent | Identifier |
|
||||||
|
| useHigherOrderComponent.jsx:17:12:17:48 | <LazyLo ... azy2"/> | useHigherOrderComponent.jsx:17:13:17:32 | LazyLoadedComponent2 | LazyLoadedComponent2 | Identifier |
|
||||||
test_JSXName_this
|
test_JSXName_this
|
||||||
| es5.js:4:12:4:45 | <div>He ... }</div> | es5.js:4:24:4:27 | this |
|
| es5.js:4:12:4:45 | <div>He ... }</div> | es5.js:4:24:4:27 | this |
|
||||||
| es5.js:20:12:20:44 | <h1>Hel ... e}</h1> | es5.js:20:24:20:27 | this |
|
| es5.js:20:12:20:44 | <h1>Hel ... e}</h1> | es5.js:20:24:20:27 | this |
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import SomeComponent from './higherOrderComponent';
|
||||||
|
import { lazy } from 'react';
|
||||||
|
|
||||||
|
function foo() {
|
||||||
|
return <SomeComponent color="red"/>
|
||||||
|
}
|
||||||
|
|
||||||
|
const LazyLoadedComponent = lazy(() => import('./higherOrderComponent'));
|
||||||
|
|
||||||
|
function bar() {
|
||||||
|
return <LazyLoadedComponent color="lazy"/>
|
||||||
|
}
|
||||||
|
|
||||||
|
const LazyLoadedComponent2 = lazy(() => import('./exportedComponent').then(m => m.MyComponent));
|
||||||
|
|
||||||
|
function barz() {
|
||||||
|
return <LazyLoadedComponent2 color="lazy2"/>
|
||||||
|
}
|
||||||
@@ -144,6 +144,33 @@ nodes
|
|||||||
| react-native.js:8:18:8:24 | tainted |
|
| react-native.js:8:18:8:24 | tainted |
|
||||||
| react-native.js:9:27:9:33 | tainted |
|
| react-native.js:9:27:9:33 | tainted |
|
||||||
| react-native.js:9:27:9:33 | tainted |
|
| react-native.js:9:27:9: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:10:22:10:32 | window.name |
|
||||||
|
| react-use-state.js:4:9:4:49 | state |
|
||||||
|
| react-use-state.js:4:10:4:14 | state |
|
||||||
|
| react-use-state.js:4:38:4:48 | window.name |
|
||||||
|
| react-use-state.js:4:38:4:48 | window.name |
|
||||||
|
| react-use-state.js:5:51:5:55 | state |
|
||||||
|
| react-use-state.js:5:51:5:55 | state |
|
||||||
|
| react-use-state.js:9:9:9:43 | state |
|
||||||
|
| react-use-state.js:9:10:9:14 | state |
|
||||||
|
| react-use-state.js:10:14:10:24 | window.name |
|
||||||
|
| react-use-state.js:10:14:10:24 | window.name |
|
||||||
|
| react-use-state.js:11:51:11:55 | state |
|
||||||
|
| react-use-state.js:11:51:11:55 | state |
|
||||||
|
| react-use-state.js:15:9:15:43 | state |
|
||||||
|
| react-use-state.js:15:10:15:14 | state |
|
||||||
|
| react-use-state.js:16:20:16:30 | window.name |
|
||||||
|
| react-use-state.js:16:20:16:30 | window.name |
|
||||||
|
| react-use-state.js:17:51:17:55 | state |
|
||||||
|
| react-use-state.js:17:51:17:55 | state |
|
||||||
|
| react-use-state.js:21:10:21:14 | state |
|
||||||
|
| react-use-state.js:22:14:22:17 | prev |
|
||||||
|
| react-use-state.js:23:35:23:38 | prev |
|
||||||
|
| react-use-state.js:23:35:23:38 | prev |
|
||||||
|
| react-use-state.js:25:20:25:30 | window.name |
|
||||||
|
| react-use-state.js:25:20:25:30 | window.name |
|
||||||
| sanitiser.js:16:7:16:27 | tainted |
|
| sanitiser.js:16:7:16:27 | tainted |
|
||||||
| sanitiser.js:16:17:16:27 | window.name |
|
| sanitiser.js:16:17:16:27 | window.name |
|
||||||
| sanitiser.js:16:17:16:27 | window.name |
|
| sanitiser.js:16:17:16:27 | window.name |
|
||||||
@@ -683,6 +710,27 @@ edges
|
|||||||
| react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted |
|
| react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted |
|
||||||
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
||||||
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
| 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-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:10:4:14 | state | react-use-state.js:4:9:4:49 | state |
|
||||||
|
| react-use-state.js:4:38:4:48 | window.name | react-use-state.js:4:10:4:14 | state |
|
||||||
|
| react-use-state.js:4:38:4:48 | window.name | react-use-state.js:4:10:4:14 | state |
|
||||||
|
| react-use-state.js:9:9:9:43 | state | react-use-state.js:11:51:11:55 | state |
|
||||||
|
| react-use-state.js:9:9:9:43 | state | react-use-state.js:11:51:11:55 | state |
|
||||||
|
| react-use-state.js:9:10:9:14 | state | react-use-state.js:9:9:9:43 | state |
|
||||||
|
| react-use-state.js:10:14:10:24 | window.name | react-use-state.js:9:10:9:14 | state |
|
||||||
|
| react-use-state.js:10:14:10:24 | window.name | react-use-state.js:9:10:9:14 | state |
|
||||||
|
| react-use-state.js:15:9:15:43 | state | react-use-state.js:17:51:17:55 | state |
|
||||||
|
| react-use-state.js:15:9:15:43 | state | react-use-state.js:17:51:17:55 | state |
|
||||||
|
| react-use-state.js:15:10:15:14 | state | react-use-state.js:15:9:15:43 | state |
|
||||||
|
| react-use-state.js:16:20:16:30 | window.name | react-use-state.js:15:10:15:14 | state |
|
||||||
|
| react-use-state.js:16:20:16:30 | window.name | react-use-state.js:15:10:15:14 | state |
|
||||||
|
| react-use-state.js:21:10:21:14 | state | react-use-state.js:22:14:22:17 | prev |
|
||||||
|
| react-use-state.js:22:14:22:17 | prev | react-use-state.js:23:35:23:38 | prev |
|
||||||
|
| react-use-state.js:22:14:22:17 | prev | react-use-state.js:23:35:23:38 | prev |
|
||||||
|
| react-use-state.js:25:20:25:30 | window.name | react-use-state.js:21:10:21:14 | state |
|
||||||
|
| react-use-state.js:25:20:25:30 | window.name | react-use-state.js:21:10:21:14 | state |
|
||||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:23:29:23:35 | tainted |
|
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:23:29:23:35 | tainted |
|
||||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:30:29:30:35 | tainted |
|
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:30:29:30:35 | tainted |
|
||||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:33:29:33:35 | tainted |
|
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:33:29:33:35 | tainted |
|
||||||
@@ -1080,6 +1128,11 @@ edges
|
|||||||
| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value |
|
| optionalSanitizer.js:45:18:45:56 | sanitiz ... target | optionalSanitizer.js:26:16:26:32 | document.location | optionalSanitizer.js:45:18:45:56 | sanitiz ... target | Cross-site scripting vulnerability due to $@. | optionalSanitizer.js:26:16:26:32 | document.location | user-provided value |
|
||||||
| react-native.js:8:18:8:24 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
|
| react-native.js:8:18:8:24 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
|
||||||
| 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-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-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 |
|
||||||
|
| react-use-state.js:23:35:23:38 | prev | react-use-state.js:25:20:25:30 | window.name | react-use-state.js:23:35:23:38 | prev | Cross-site scripting vulnerability due to $@. | react-use-state.js:25:20:25:30 | window.name | user-provided value |
|
||||||
| sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
| sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:23:21:23:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
||||||
| sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
| sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:30:21:30:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
||||||
| sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
| sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' | sanitiser.js:16:17:16:27 | window.name | sanitiser.js:33:21:33:44 | '<b>' + ... '</b>' | Cross-site scripting vulnerability due to $@. | sanitiser.js:16:17:16:27 | window.name | user-provided value |
|
||||||
|
|||||||
@@ -144,6 +144,33 @@ nodes
|
|||||||
| react-native.js:8:18:8:24 | tainted |
|
| react-native.js:8:18:8:24 | tainted |
|
||||||
| react-native.js:9:27:9:33 | tainted |
|
| react-native.js:9:27:9:33 | tainted |
|
||||||
| react-native.js:9:27:9:33 | tainted |
|
| react-native.js:9:27:9: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:10:22:10:32 | window.name |
|
||||||
|
| react-use-state.js:4:9:4:49 | state |
|
||||||
|
| react-use-state.js:4:10:4:14 | state |
|
||||||
|
| react-use-state.js:4:38:4:48 | window.name |
|
||||||
|
| react-use-state.js:4:38:4:48 | window.name |
|
||||||
|
| react-use-state.js:5:51:5:55 | state |
|
||||||
|
| react-use-state.js:5:51:5:55 | state |
|
||||||
|
| react-use-state.js:9:9:9:43 | state |
|
||||||
|
| react-use-state.js:9:10:9:14 | state |
|
||||||
|
| react-use-state.js:10:14:10:24 | window.name |
|
||||||
|
| react-use-state.js:10:14:10:24 | window.name |
|
||||||
|
| react-use-state.js:11:51:11:55 | state |
|
||||||
|
| react-use-state.js:11:51:11:55 | state |
|
||||||
|
| react-use-state.js:15:9:15:43 | state |
|
||||||
|
| react-use-state.js:15:10:15:14 | state |
|
||||||
|
| react-use-state.js:16:20:16:30 | window.name |
|
||||||
|
| react-use-state.js:16:20:16:30 | window.name |
|
||||||
|
| react-use-state.js:17:51:17:55 | state |
|
||||||
|
| react-use-state.js:17:51:17:55 | state |
|
||||||
|
| react-use-state.js:21:10:21:14 | state |
|
||||||
|
| react-use-state.js:22:14:22:17 | prev |
|
||||||
|
| react-use-state.js:23:35:23:38 | prev |
|
||||||
|
| react-use-state.js:23:35:23:38 | prev |
|
||||||
|
| react-use-state.js:25:20:25:30 | window.name |
|
||||||
|
| react-use-state.js:25:20:25:30 | window.name |
|
||||||
| sanitiser.js:16:7:16:27 | tainted |
|
| sanitiser.js:16:7:16:27 | tainted |
|
||||||
| sanitiser.js:16:17:16:27 | window.name |
|
| sanitiser.js:16:17:16:27 | window.name |
|
||||||
| sanitiser.js:16:17:16:27 | window.name |
|
| sanitiser.js:16:17:16:27 | window.name |
|
||||||
@@ -687,6 +714,27 @@ edges
|
|||||||
| react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted |
|
| react-native.js:7:7:7:33 | tainted | react-native.js:9:27:9:33 | tainted |
|
||||||
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
||||||
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
| 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-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:10:4:14 | state | react-use-state.js:4:9:4:49 | state |
|
||||||
|
| react-use-state.js:4:38:4:48 | window.name | react-use-state.js:4:10:4:14 | state |
|
||||||
|
| react-use-state.js:4:38:4:48 | window.name | react-use-state.js:4:10:4:14 | state |
|
||||||
|
| react-use-state.js:9:9:9:43 | state | react-use-state.js:11:51:11:55 | state |
|
||||||
|
| react-use-state.js:9:9:9:43 | state | react-use-state.js:11:51:11:55 | state |
|
||||||
|
| react-use-state.js:9:10:9:14 | state | react-use-state.js:9:9:9:43 | state |
|
||||||
|
| react-use-state.js:10:14:10:24 | window.name | react-use-state.js:9:10:9:14 | state |
|
||||||
|
| react-use-state.js:10:14:10:24 | window.name | react-use-state.js:9:10:9:14 | state |
|
||||||
|
| react-use-state.js:15:9:15:43 | state | react-use-state.js:17:51:17:55 | state |
|
||||||
|
| react-use-state.js:15:9:15:43 | state | react-use-state.js:17:51:17:55 | state |
|
||||||
|
| react-use-state.js:15:10:15:14 | state | react-use-state.js:15:9:15:43 | state |
|
||||||
|
| react-use-state.js:16:20:16:30 | window.name | react-use-state.js:15:10:15:14 | state |
|
||||||
|
| react-use-state.js:16:20:16:30 | window.name | react-use-state.js:15:10:15:14 | state |
|
||||||
|
| react-use-state.js:21:10:21:14 | state | react-use-state.js:22:14:22:17 | prev |
|
||||||
|
| react-use-state.js:22:14:22:17 | prev | react-use-state.js:23:35:23:38 | prev |
|
||||||
|
| react-use-state.js:22:14:22:17 | prev | react-use-state.js:23:35:23:38 | prev |
|
||||||
|
| react-use-state.js:25:20:25:30 | window.name | react-use-state.js:21:10:21:14 | state |
|
||||||
|
| react-use-state.js:25:20:25:30 | window.name | react-use-state.js:21:10:21:14 | state |
|
||||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:23:29:23:35 | tainted |
|
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:23:29:23:35 | tainted |
|
||||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:30:29:30:35 | tainted |
|
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:30:29:30:35 | tainted |
|
||||||
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:33:29:33:35 | tainted |
|
| sanitiser.js:16:7:16:27 | tainted | sanitiser.js:33:29:33:35 | tainted |
|
||||||
|
|||||||
3
javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-create-context.js
vendored
Normal file
3
javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-create-context.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { createContext } from 'react';
|
||||||
|
|
||||||
|
export let MyContext = createContext({root: null});
|
||||||
5
javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-provide-context.js
vendored
Normal file
5
javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-provide-context.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { MyContext } from './react-create-context';
|
||||||
|
|
||||||
|
export function renderMain() {
|
||||||
|
return <MyContext.Provider value={{root: document.body}}></MyContext.Provider>
|
||||||
|
}
|
||||||
11
javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-context.js
vendored
Normal file
11
javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-context.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { MyContext } from './react-create-context';
|
||||||
|
|
||||||
|
function useMyContext() {
|
||||||
|
return useContext(MyContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDoc1() {
|
||||||
|
let { root } = useMyContext();
|
||||||
|
root.appendChild(window.name); // NOT OK
|
||||||
|
}
|
||||||
33
javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-state.js
vendored
Normal file
33
javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/react-use-state.js
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
function initialState() {
|
||||||
|
let [state, setState] = useState(window.name);
|
||||||
|
return <div dangerouslySetInnerHTML={{__html: state}}></div>; // NOT OK
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStateValue() {
|
||||||
|
let [state, setState] = useState('foo');
|
||||||
|
setState(window.name);
|
||||||
|
return <div dangerouslySetInnerHTML={{__html: state}}></div>; // NOT OK
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStateValueLazy() {
|
||||||
|
let [state, setState] = useState('foo');
|
||||||
|
setState(() => window.name);
|
||||||
|
return <div dangerouslySetInnerHTML={{__html: state}}></div>; // NOT OK
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStateValueLazy() {
|
||||||
|
let [state, setState] = useState('foo');
|
||||||
|
setState(prev => {
|
||||||
|
document.body.innerHTML = prev; // NOT OK
|
||||||
|
})
|
||||||
|
setState(() => window.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStateValueSafe() {
|
||||||
|
let [state, setState] = useState('foo');
|
||||||
|
setState('safe');
|
||||||
|
setState(() => 'also safe');
|
||||||
|
return <div dangerouslySetInnerHTML={{__html: state}}></div>; // OK
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user