mirror of
https://github.com/github/codeql.git
synced 2026-05-02 04:05:14 +02:00
3
javascript/change-notes/2021-02-18-next-js.md
Normal file
3
javascript/change-notes/2021-02-18-next-js.md
Normal file
@@ -0,0 +1,3 @@
|
||||
lgtm,codescanning
|
||||
* Support for [Next.js](https://www.npmjs.com/package/next) has been added.
|
||||
Taint sources, sinks, and steps are now recognized.
|
||||
@@ -97,6 +97,7 @@ import semmle.javascript.frameworks.Logging
|
||||
import semmle.javascript.frameworks.HttpFrameworks
|
||||
import semmle.javascript.frameworks.HttpProxy
|
||||
import semmle.javascript.frameworks.Markdown
|
||||
import semmle.javascript.frameworks.Next
|
||||
import semmle.javascript.frameworks.NoSQL
|
||||
import semmle.javascript.frameworks.PkgCloud
|
||||
import semmle.javascript.frameworks.PropertyProjection
|
||||
|
||||
@@ -491,4 +491,11 @@ module DOM {
|
||||
or
|
||||
result.hasUnderlyingType("Document")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a value assigned to property `name` of a DOM node can be interpreted as JavaScript via the `javascript:` protocol.
|
||||
*/
|
||||
string getAPropertyNameInterpretedAsJavaScriptUrl() {
|
||||
result = ["action", "formaction", "href", "src", "data"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,12 @@ class JSXElement extends JSXNode {
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "JSXElement" }
|
||||
|
||||
/**
|
||||
* Holds if this JSX element is a HTML element.
|
||||
* That is, the name starts with a lowercase letter.
|
||||
*/
|
||||
predicate isHTMLElement() { getName().regexpMatch("[a-z].*") }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
240
javascript/ql/src/semmle/javascript/frameworks/Next.qll
Normal file
240
javascript/ql/src/semmle/javascript/frameworks/Next.qll
Normal file
@@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Provides classes and predicates for reasoning about [Next.js](https://www.npmjs.com/package/next).
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* Provides classes and predicates modelling [Next.js](https://www.npmjs.com/package/next).
|
||||
*/
|
||||
module NextJS {
|
||||
/**
|
||||
* Gets a `package.json` that depends on the `Next.js` library.
|
||||
*/
|
||||
PackageJSON getANextPackage() { result.getDependencies().getADependency("next", _) }
|
||||
|
||||
/**
|
||||
* Gets a "pages" folder in a `Next.js` application.
|
||||
* JavaScript files inside these folders are mapped to routes.
|
||||
*/
|
||||
Folder getAPagesFolder() {
|
||||
result = getANextPackage().getFile().getParentContainer().getFolder("pages")
|
||||
or
|
||||
result = getAPagesFolder().getAFolder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a module corrosponding to a `Next.js` page.
|
||||
*/
|
||||
Module getAPagesModule() { result.getFile().getParentContainer() = getAPagesFolder() }
|
||||
|
||||
/**
|
||||
* Gets a module inside a "pages" folder where `fallback` from `getStaticPaths` is not set to false.
|
||||
* In such a module the `getStaticProps` method can be called with user-defined parameters.
|
||||
* If `fallback` is set to false, then only values defined by `getStaticPaths` are allowed.
|
||||
*/
|
||||
Module getAModuleWithFallbackPaths() {
|
||||
result = getAPagesModule() and
|
||||
exists(DataFlow::FunctionNode staticPaths, Expr fallback |
|
||||
staticPaths = result.getAnExportedValue("getStaticPaths").getAFunctionValue() and
|
||||
fallback =
|
||||
staticPaths.getAReturn().getALocalSource().getAPropertyWrite("fallback").getRhs().asExpr() and
|
||||
not fallback.(BooleanLiteral).getValue() = "false"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* User defined path parameter in `Next.js`.
|
||||
*/
|
||||
class NextParams extends RemoteFlowSource {
|
||||
NextParams() {
|
||||
this =
|
||||
getAModuleWithFallbackPaths()
|
||||
.getAnExportedValue("getStaticProps")
|
||||
.getAFunctionValue()
|
||||
.getParameter(0)
|
||||
.getAPropertyRead("params")
|
||||
}
|
||||
|
||||
override string getSourceType() { result = "Next request parameter" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `getStaticProps` function in a Next.js page.
|
||||
* This function is executed at build time, or when a page with a new URL is requested for the first time (if `fallback` is not false).
|
||||
*/
|
||||
DataFlow::FunctionNode getStaticPropsFunction(Module pageModule) {
|
||||
pageModule = getAPagesModule() and
|
||||
result = pageModule.getAnExportedValue("getStaticProps").getAFunctionValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `getServerSideProps` function in a Next.js page.
|
||||
* This function is executed on the server every time a request for the page is made.
|
||||
* The function receives a context parameter, which includes HTTP request/response objects.
|
||||
*/
|
||||
DataFlow::FunctionNode getServerSidePropsFunction(Module pageModule) {
|
||||
pageModule = getAPagesModule() and
|
||||
result = pageModule.getAnExportedValue("getServerSideProps").getAFunctionValue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `getInitialProps` function in a Next.js page.
|
||||
* This function is executed on the server every time a request for the page is made.
|
||||
* The function receives a context parameter, which includes HTTP request/response objects.
|
||||
*/
|
||||
DataFlow::FunctionNode getInitialProps(Module pageModule) {
|
||||
pageModule = getAPagesModule() and
|
||||
(
|
||||
result =
|
||||
pageModule
|
||||
.getAnExportedValue("default")
|
||||
.getAFunctionValue()
|
||||
.getAPropertyWrite("getInitialProps")
|
||||
.getRhs()
|
||||
.getAFunctionValue()
|
||||
or
|
||||
result =
|
||||
pageModule
|
||||
.getAnExportedValue("default")
|
||||
.getALocalSource()
|
||||
.getAstNode()
|
||||
.(ReactComponent)
|
||||
.getStaticMethod("getInitialProps")
|
||||
.flow()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to a `props` object computed by the Next.js server.
|
||||
* This `props` object is both used both by the server and client to render the page.
|
||||
*/
|
||||
DataFlow::Node getAPropsSource(Module pageModule) {
|
||||
pageModule = getAPagesModule() and
|
||||
(
|
||||
result =
|
||||
[getStaticPropsFunction(pageModule), getServerSidePropsFunction(pageModule)]
|
||||
.getAReturn()
|
||||
.getALocalSource()
|
||||
.getAPropertyWrite("props")
|
||||
.getRhs()
|
||||
or
|
||||
result = getInitialProps(pageModule).getAReturn()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A step modelling the flow from the server-computed props object to the default exported function that renders the page.
|
||||
*/
|
||||
class NextJSStaticPropsStep extends DataFlow::AdditionalFlowStep, DataFlow::FunctionNode {
|
||||
Module pageModule;
|
||||
|
||||
NextJSStaticPropsStep() {
|
||||
pageModule = getAPagesModule() and
|
||||
this = pageModule.getAnExportedValue("default").getAFunctionValue()
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = getAPropsSource(pageModule) and
|
||||
succ = this.getParameter(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step modelling the flow from the server-computed props object to the default exported React component that renders the page.
|
||||
*/
|
||||
class NextJSStaticReactComponentPropsStep extends DataFlow::AdditionalFlowStep,
|
||||
DataFlow::ValueNode {
|
||||
Module pageModule;
|
||||
ReactComponent component;
|
||||
|
||||
NextJSStaticReactComponentPropsStep() {
|
||||
pageModule = getAPagesModule() and
|
||||
this.getAstNode() = component and
|
||||
this = pageModule.getAnExportedValue("default").getALocalSource()
|
||||
}
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = getAPropsSource(pageModule) and
|
||||
succ = component.getADirectPropsAccess()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Next.js function that is exected on the server for every request, seen as a routehandler.
|
||||
*/
|
||||
class NextHttpRouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::FunctionNode {
|
||||
Module pageModule;
|
||||
|
||||
NextHttpRouteHandler() {
|
||||
this = getServerSidePropsFunction(pageModule) or this = getInitialProps(pageModule)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A NodeJS HTTP request object in a Next.js page.
|
||||
*/
|
||||
class NextHttpRequestSource extends NodeJSLib::RequestSource {
|
||||
NextHttpRouteHandler rh;
|
||||
|
||||
NextHttpRequestSource() { this = rh.getParameter(0).getAPropertyRead("req") }
|
||||
|
||||
override HTTP::RouteHandler getRouteHandler() { result = rh }
|
||||
}
|
||||
|
||||
/**
|
||||
* A NodeJS HTTP response object in a Next.js page.
|
||||
*/
|
||||
class NextHttpResponseSource extends NodeJSLib::ResponseSource {
|
||||
NextHttpRouteHandler rh;
|
||||
|
||||
NextHttpResponseSource() { this = rh.getParameter(0).getAPropertyRead("res") }
|
||||
|
||||
override HTTP::RouteHandler getRouteHandler() { result = rh }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a folder that contains API endpoints for a Next.js application.
|
||||
* These API endpoints act as Express-like route-handlers.
|
||||
*/
|
||||
Folder apiFolder() {
|
||||
result = getANextPackage().getFile().getParentContainer().getFolder("pages").getFolder("api")
|
||||
or
|
||||
result = apiFolder().getAFolder()
|
||||
}
|
||||
|
||||
/**
|
||||
* A Next.js route handler for an API endpoint.
|
||||
* The response (res) includes a set of Express.js-like methods,
|
||||
* and we therefore model the routehandler as an Express.js routehandler.
|
||||
*/
|
||||
class NextAPIRouteHandler extends DataFlow::FunctionNode, Express::RouteHandler,
|
||||
HTTP::Servers::StandardRouteHandler {
|
||||
NextAPIRouteHandler() {
|
||||
exists(Module mod | mod.getFile().getParentContainer() = apiFolder() |
|
||||
this = mod.getAnExportedValue("default").getAFunctionValue()
|
||||
)
|
||||
}
|
||||
|
||||
override Parameter getRouteHandlerParameter(string kind) {
|
||||
kind = "request" and result = getFunction().getParameter(0)
|
||||
or
|
||||
kind = "response" and result = getFunction().getParameter(1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to a [Next.js router](https://nextjs.org/docs/api-reference/next/router).
|
||||
*/
|
||||
DataFlow::SourceNode nextRouter() {
|
||||
result = DataFlow::moduleMember("next/router", "useRouter").getACall()
|
||||
or
|
||||
result =
|
||||
API::moduleImport("next/router")
|
||||
.getMember("withRouter")
|
||||
.getParameter(0)
|
||||
.getParameter(0)
|
||||
.getMember("router")
|
||||
.getAnImmediateUse()
|
||||
}
|
||||
}
|
||||
@@ -107,13 +107,18 @@ module NodeJSLib {
|
||||
}
|
||||
|
||||
/**
|
||||
* A Node.js response source, that is, the response parameter of a
|
||||
* A Node.js response source.
|
||||
*/
|
||||
abstract class ResponseSource extends HTTP::Servers::ResponseSource { }
|
||||
|
||||
/**
|
||||
* A standard Node.js response source, that is, the response parameter of a
|
||||
* route handler.
|
||||
*/
|
||||
private class ResponseSource extends HTTP::Servers::ResponseSource {
|
||||
private class StandardResponseSource extends ResponseSource {
|
||||
RouteHandler rh;
|
||||
|
||||
ResponseSource() { this = DataFlow::parameterNode(rh.getResponseParameter()) }
|
||||
StandardResponseSource() { this = DataFlow::parameterNode(rh.getResponseParameter()) }
|
||||
|
||||
/**
|
||||
* Gets the route handler that provides this response.
|
||||
@@ -122,13 +127,18 @@ module NodeJSLib {
|
||||
}
|
||||
|
||||
/**
|
||||
* A Node.js request source, that is, the request parameter of a
|
||||
* A Node.js request source.
|
||||
*/
|
||||
abstract class RequestSource extends HTTP::Servers::RequestSource { }
|
||||
|
||||
/**
|
||||
* A standard Node.js request source, that is, the request parameter of a
|
||||
* route handler.
|
||||
*/
|
||||
private class RequestSource extends HTTP::Servers::RequestSource {
|
||||
private class StandardRequestSource extends RequestSource {
|
||||
RouteHandler rh;
|
||||
|
||||
RequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) }
|
||||
StandardRequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) }
|
||||
|
||||
/**
|
||||
* Gets the route handler that handles this request.
|
||||
|
||||
@@ -166,4 +166,29 @@ module ClientSideUrlRedirect {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A write to an React attribute which may execute JavaScript code.
|
||||
*/
|
||||
class ReactAttributeWriteUrlSink extends ScriptUrlSink {
|
||||
ReactAttributeWriteUrlSink() {
|
||||
exists(JSXAttribute attr |
|
||||
attr.getName() = DOM::getAPropertyNameInterpretedAsJavaScriptUrl() and
|
||||
attr.getElement().isHTMLElement()
|
||||
or
|
||||
DataFlow::moduleImport("next/link").flowsToExpr(attr.getElement().getNameExpr())
|
||||
|
|
||||
this = attr.getValue().flow()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to change the current url with a Next.js router.
|
||||
*/
|
||||
class NextRoutePushUrlSink extends ScriptUrlSink {
|
||||
NextRoutePushUrlSink() {
|
||||
this = NextJS::nextRouter().getAMemberCall(["push", "replace"]).getArgument(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,11 +122,7 @@ class DomPropWriteNode extends Assignment {
|
||||
* Holds if the assigned value is interpreted as JavaScript via javascript: protocol.
|
||||
*/
|
||||
predicate interpretsValueAsJavaScriptUrl() {
|
||||
lhs.getPropertyName() = "action" or
|
||||
lhs.getPropertyName() = "formaction" or
|
||||
lhs.getPropertyName() = "href" or
|
||||
lhs.getPropertyName() = "src" or
|
||||
lhs.getPropertyName() = "data"
|
||||
lhs.getPropertyName() = DOM::getAPropertyNameInterpretedAsJavaScriptUrl()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "my-app",
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "^10.0.0",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: [],
|
||||
fallback: true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function getStaticProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
id: params.id,
|
||||
taint: source()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function Post({ taint, stars, more }) {
|
||||
sink(taint);
|
||||
sink(stars);
|
||||
sink(more);
|
||||
return <span />;
|
||||
}
|
||||
|
||||
Post.getInitialProps = async (ctx) => {
|
||||
return { stars: source(2) }
|
||||
}
|
||||
|
||||
export async function getServerSideProps(ctx) {
|
||||
return {
|
||||
props: {
|
||||
more: source(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import React from 'react'
|
||||
|
||||
class Page extends React.Component {
|
||||
static async getInitialProps(ctx) {
|
||||
const url = ctx.req.url;
|
||||
return { stars: json.stargazers_count, taint: source(1) }
|
||||
}
|
||||
|
||||
render() {
|
||||
sink(this.props.taint);
|
||||
return <div>Next stars: {this.props.stars}</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,8 @@
|
||||
remoteFlow
|
||||
| pages/[my-fallback-id].jsx:9:40:9:45 | params |
|
||||
| pages/secondpage.jsx:5:17:5:27 | ctx.req.url |
|
||||
dataFlow
|
||||
| pages/[my-fallback-id].jsx:13:20:13:27 | source() | pages/[my-fallback-id].jsx:19:10:19:14 | taint |
|
||||
| pages/[my-fallback-id].jsx:26:21:26:29 | source(2) | pages/[my-fallback-id].jsx:20:10:20:14 | stars |
|
||||
| pages/[my-fallback-id].jsx:32:19:32:27 | source(3) | pages/[my-fallback-id].jsx:21:10:21:13 | more |
|
||||
| pages/secondpage.jsx:6:51:6:59 | source(1) | pages/secondpage.jsx:10:10:10:25 | this.props.taint |
|
||||
19
javascript/ql/test/library-tests/frameworks/Next/tests.ql
Normal file
19
javascript/ql/test/library-tests/frameworks/Next/tests.ql
Normal file
@@ -0,0 +1,19 @@
|
||||
import javascript
|
||||
|
||||
query RemoteFlowSource remoteFlow() { any() }
|
||||
|
||||
class Config extends DataFlow::Configuration {
|
||||
Config() { this = "Config" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.(DataFlow::CallNode).getCalleeName() = "source"
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlow::CallNode call | call.getCalleeName() = "sink" | call.getAnArgument() = sink)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate dataFlow(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
any(Config c).hasFlow(pred, succ)
|
||||
}
|
||||
@@ -103,6 +103,15 @@ nodes
|
||||
| formatting.js:7:14:7:53 | require ... , evil) |
|
||||
| formatting.js:7:14:7:53 | require ... , evil) |
|
||||
| formatting.js:7:49:7:52 | evil |
|
||||
| pages/Next.jsx:8:13:8:19 | req.url |
|
||||
| pages/Next.jsx:8:13:8:19 | req.url |
|
||||
| pages/Next.jsx:8:13:8:19 | req.url |
|
||||
| pages/Next.jsx:15:13:15:19 | req.url |
|
||||
| pages/Next.jsx:15:13:15:19 | req.url |
|
||||
| pages/Next.jsx:15:13:15:19 | req.url |
|
||||
| pages/api/myapi.js:2:14:2:20 | req.url |
|
||||
| pages/api/myapi.js:2:14:2:20 | req.url |
|
||||
| pages/api/myapi.js:2:14:2:20 | req.url |
|
||||
| partial.js:9:25:9:25 | x |
|
||||
| partial.js:10:14:10:14 | x |
|
||||
| partial.js:10:14:10:18 | x + y |
|
||||
@@ -237,6 +246,9 @@ edges
|
||||
| formatting.js:6:43:6:46 | evil | formatting.js:6:14:6:47 | util.fo ... , evil) |
|
||||
| formatting.js:7:49:7:52 | evil | formatting.js:7:14:7:53 | require ... , evil) |
|
||||
| formatting.js:7:49:7:52 | evil | formatting.js:7:14:7:53 | require ... , evil) |
|
||||
| pages/Next.jsx:8:13:8:19 | req.url | pages/Next.jsx:8:13:8:19 | req.url |
|
||||
| pages/Next.jsx:15:13:15:19 | req.url | pages/Next.jsx:15:13:15:19 | req.url |
|
||||
| pages/api/myapi.js:2:14:2:20 | req.url | pages/api/myapi.js:2:14:2:20 | req.url |
|
||||
| partial.js:9:25:9:25 | x | partial.js:10:14:10:14 | x |
|
||||
| partial.js:10:14:10:14 | x | partial.js:10:14:10:18 | x + y |
|
||||
| partial.js:10:14:10:14 | x | partial.js:10:14:10:18 | x + y |
|
||||
@@ -303,6 +315,9 @@ edges
|
||||
| etherpad.js:11:12:11:19 | response | etherpad.js:9:16:9:30 | req.query.jsonp | etherpad.js:11:12:11:19 | response | Cross-site scripting vulnerability due to $@. | etherpad.js:9:16:9:30 | req.query.jsonp | user-provided value |
|
||||
| formatting.js:6:14:6:47 | util.fo ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
|
||||
| formatting.js:7:14:7:53 | require ... , evil) | formatting.js:4:16:4:29 | req.query.evil | formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
|
||||
| pages/Next.jsx:8:13:8:19 | req.url | pages/Next.jsx:8:13:8:19 | req.url | pages/Next.jsx:8:13:8:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:8:13:8:19 | req.url | user-provided value |
|
||||
| pages/Next.jsx:15:13:15:19 | req.url | pages/Next.jsx:15:13:15:19 | req.url | pages/Next.jsx:15:13:15:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:15:13:15:19 | req.url | user-provided value |
|
||||
| pages/api/myapi.js:2:14:2:20 | req.url | pages/api/myapi.js:2:14:2:20 | req.url | pages/api/myapi.js:2:14:2:20 | req.url | Cross-site scripting vulnerability due to $@. | pages/api/myapi.js:2:14:2:20 | req.url | user-provided value |
|
||||
| partial.js:10:14:10:18 | x + y | partial.js:13:42:13:48 | req.url | partial.js:10:14:10:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:13:42:13:48 | req.url | user-provided value |
|
||||
| partial.js:19:14:19:18 | x + y | partial.js:22:51:22:57 | req.url | partial.js:19:14:19:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:22:51:22:57 | req.url | user-provided value |
|
||||
| partial.js:28:14:28:18 | x + y | partial.js:31:47:31:53 | req.url | partial.js:28:14:28:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:31:47:31:53 | req.url | user-provided value |
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
| ReflectedXssGood3.js:139:12:139:27 | escapeHtml3(url) | Cross-site scripting vulnerability due to $@. | ReflectedXssGood3.js:135:15:135:27 | req.params.id | user-provided value |
|
||||
| formatting.js:6:14:6:47 | util.fo ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
|
||||
| formatting.js:7:14:7:53 | require ... , evil) | Cross-site scripting vulnerability due to $@. | formatting.js:4:16:4:29 | req.query.evil | user-provided value |
|
||||
| pages/Next.jsx:8:13:8:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:8:13:8:19 | req.url | user-provided value |
|
||||
| pages/Next.jsx:15:13:15:19 | req.url | Cross-site scripting vulnerability due to $@. | pages/Next.jsx:15:13:15:19 | req.url | user-provided value |
|
||||
| pages/api/myapi.js:2:14:2:20 | req.url | Cross-site scripting vulnerability due to $@. | pages/api/myapi.js:2:14:2:20 | req.url | user-provided value |
|
||||
| partial.js:10:14:10:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:13:42:13:48 | req.url | user-provided value |
|
||||
| partial.js:19:14:19:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:22:51:22:57 | req.url | user-provided value |
|
||||
| partial.js:28:14:28:18 | x + y | Cross-site scripting vulnerability due to $@. | partial.js:31:47:31:53 | req.url | user-provided value |
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "my-app",
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "^10.0.0",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
export default function Post() {
|
||||
return <span />;
|
||||
}
|
||||
|
||||
Post.getInitialProps = async (ctx) => {
|
||||
const req = ctx.req;
|
||||
const res = ctx.res;
|
||||
res.end(req.url);
|
||||
return {}
|
||||
}
|
||||
|
||||
export async function getServerSideProps(ctx) {
|
||||
const req = ctx.req;
|
||||
const res = ctx.res;
|
||||
res.end(req.url);
|
||||
return {
|
||||
props: {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export default function handler(req, res) {
|
||||
res.send(req.url);
|
||||
}
|
||||
@@ -7,6 +7,25 @@ nodes
|
||||
| react.js:10:60:10:76 | document.location |
|
||||
| react.js:10:60:10:81 | documen ... on.hash |
|
||||
| react.js:10:60:10:81 | documen ... on.hash |
|
||||
| react.js:21:24:21:40 | document.location |
|
||||
| react.js:21:24:21:40 | document.location |
|
||||
| react.js:21:24:21:45 | documen ... on.hash |
|
||||
| react.js:21:24:21:45 | documen ... on.hash |
|
||||
| react.js:28:43:28:59 | document.location |
|
||||
| react.js:28:43:28:59 | document.location |
|
||||
| react.js:28:43:28:64 | documen ... on.hash |
|
||||
| react.js:28:43:28:74 | documen ... bstr(1) |
|
||||
| react.js:28:43:28:74 | documen ... bstr(1) |
|
||||
| react.js:34:43:34:59 | document.location |
|
||||
| react.js:34:43:34:59 | document.location |
|
||||
| react.js:34:43:34:64 | documen ... on.hash |
|
||||
| react.js:34:43:34:74 | documen ... bstr(1) |
|
||||
| react.js:34:43:34:74 | documen ... bstr(1) |
|
||||
| react.js:40:19:40:35 | document.location |
|
||||
| react.js:40:19:40:35 | document.location |
|
||||
| react.js:40:19:40:40 | documen ... on.hash |
|
||||
| react.js:40:19:40:50 | documen ... bstr(1) |
|
||||
| react.js:40:19:40:50 | documen ... bstr(1) |
|
||||
| sanitizer.js:2:9:2:25 | url |
|
||||
| sanitizer.js:2:15:2:25 | window.name |
|
||||
| sanitizer.js:2:15:2:25 | window.name |
|
||||
@@ -197,6 +216,22 @@ edges
|
||||
| react.js:10:60:10:76 | document.location | react.js:10:60:10:81 | documen ... on.hash |
|
||||
| react.js:10:60:10:76 | document.location | react.js:10:60:10:81 | documen ... on.hash |
|
||||
| react.js:10:60:10:76 | document.location | react.js:10:60:10:81 | documen ... on.hash |
|
||||
| react.js:21:24:21:40 | document.location | react.js:21:24:21:45 | documen ... on.hash |
|
||||
| react.js:21:24:21:40 | document.location | react.js:21:24:21:45 | documen ... on.hash |
|
||||
| react.js:21:24:21:40 | document.location | react.js:21:24:21:45 | documen ... on.hash |
|
||||
| react.js:21:24:21:40 | document.location | react.js:21:24:21:45 | documen ... on.hash |
|
||||
| react.js:28:43:28:59 | document.location | react.js:28:43:28:64 | documen ... on.hash |
|
||||
| react.js:28:43:28:59 | document.location | react.js:28:43:28:64 | documen ... on.hash |
|
||||
| react.js:28:43:28:64 | documen ... on.hash | react.js:28:43:28:74 | documen ... bstr(1) |
|
||||
| react.js:28:43:28:64 | documen ... on.hash | react.js:28:43:28:74 | documen ... bstr(1) |
|
||||
| react.js:34:43:34:59 | document.location | react.js:34:43:34:64 | documen ... on.hash |
|
||||
| react.js:34:43:34:59 | document.location | react.js:34:43:34:64 | documen ... on.hash |
|
||||
| react.js:34:43:34:64 | documen ... on.hash | react.js:34:43:34:74 | documen ... bstr(1) |
|
||||
| react.js:34:43:34:64 | documen ... on.hash | react.js:34:43:34:74 | documen ... bstr(1) |
|
||||
| react.js:40:19:40:35 | document.location | react.js:40:19:40:40 | documen ... on.hash |
|
||||
| react.js:40:19:40:35 | document.location | react.js:40:19:40:40 | documen ... on.hash |
|
||||
| react.js:40:19:40:40 | documen ... on.hash | react.js:40:19:40:50 | documen ... bstr(1) |
|
||||
| react.js:40:19:40:40 | documen ... on.hash | react.js:40:19:40:50 | documen ... bstr(1) |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:4:27:4:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:4:27:4:29 | url |
|
||||
| sanitizer.js:2:9:2:25 | url | sanitizer.js:16:27:16:29 | url |
|
||||
@@ -367,6 +402,10 @@ edges
|
||||
#select
|
||||
| electron.js:7:20:7:29 | getTaint() | electron.js:4:12:4:22 | window.name | electron.js:7:20:7:29 | getTaint() | Untrusted URL redirection due to $@. | electron.js:4:12:4:22 | window.name | user-provided value |
|
||||
| react.js:10:60:10:81 | documen ... on.hash | react.js:10:60:10:76 | document.location | react.js:10:60:10:81 | documen ... on.hash | Untrusted URL redirection due to $@. | react.js:10:60:10:76 | document.location | user-provided value |
|
||||
| react.js:21:24:21:45 | documen ... on.hash | react.js:21:24:21:40 | document.location | react.js:21:24:21:45 | documen ... on.hash | Untrusted URL redirection due to $@. | react.js:21:24:21:40 | document.location | user-provided value |
|
||||
| react.js:28:43:28:74 | documen ... bstr(1) | react.js:28:43:28:59 | document.location | react.js:28:43:28:74 | documen ... bstr(1) | Untrusted URL redirection due to $@. | react.js:28:43:28:59 | document.location | user-provided value |
|
||||
| react.js:34:43:34:74 | documen ... bstr(1) | react.js:34:43:34:59 | document.location | react.js:34:43:34:74 | documen ... bstr(1) | Untrusted URL redirection due to $@. | react.js:34:43:34:59 | document.location | user-provided value |
|
||||
| react.js:40:19:40:50 | documen ... bstr(1) | react.js:40:19:40:35 | document.location | react.js:40:19:40:50 | documen ... bstr(1) | Untrusted URL redirection due to $@. | react.js:40:19:40:35 | document.location | user-provided value |
|
||||
| sanitizer.js:4:27:4:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:4:27:4:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
| sanitizer.js:16:27:16:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:16:27:16:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
| sanitizer.js:19:27:19:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:19:27:19:29 | url | Untrusted URL redirection due to $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
|
||||
|
||||
@@ -15,3 +15,31 @@ class Application extends React.Component {
|
||||
};
|
||||
|
||||
export default Application
|
||||
|
||||
import Link from 'next/link'
|
||||
export function NextLink() {
|
||||
return <Link href={document.location.hash}><a>this page!</a></Link>;
|
||||
}
|
||||
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export function nextRouter() {
|
||||
const router = useRouter();
|
||||
return <span onClick={() => router.push(document.location.hash.substr(1))}>Click to XSS 1</span>
|
||||
}
|
||||
|
||||
import { withRouter } from 'next/router'
|
||||
|
||||
function Page({ router }) {
|
||||
return <span onClick={() => router.push(document.location.hash.substr(1))}>Click to XSS 2</span>
|
||||
}
|
||||
|
||||
export const pageWithRouter = withRouter(Page);
|
||||
|
||||
export function plainLink() {
|
||||
return <a href={document.location.hash.substr(1)}>my plain link!</a>;
|
||||
}
|
||||
|
||||
export function someUnknown() {
|
||||
return <FOO data={document.location.hash.substr(1)}>is safe.</FOO>;
|
||||
}
|
||||
Reference in New Issue
Block a user