Merge pull request #3099 from esbena/js/introduce-poi-utility

Approved by erik-krogh
This commit is contained in:
semmle-qlci 2020-04-23 12:14:00 +01:00 коммит произвёл GitHub
Родитель 312e6229fb a66b4b55fe
Коммит 801ce89c67
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
18 изменённых файлов: 563 добавлений и 79 удалений

Просмотреть файл

@ -0,0 +1,325 @@
/**
* Provides classes and predicates for discovering points of interest
* in an unknown code base.
*
* To use this module, subclass the
* `ActivePoI` class, override *one* of its `is` predicates, and use
* `alertQuery` as a `@kind problem` query . This will present
* the desired points of interest as alerts that are easily browsable
* in a codeql IDE. By itself, this is no different from an ordinary
* query, but the strength of this module lies in its extensibility
* and standard library:
*
* - points of interest can be added, removed and mixed seamlessly
* - this module comes with a collection of standard points of interest (see `StandardPoIs`)
*
* A global configuration for the points of interest (see
* `PoIConfiguration`) can be used to easily manage multiple points of
* interests, and to restrict the points of interest to specific
* corners of the code base.
*
* Below is an example use of this module that will produce an alert
* for each route handler and route handler setup in a file named
* "server-core.js". The route setup alerts will contain a link to its
* associated route handler.
*
* ```
* /**
* * @kind problem
* *\/
*
* import PoI
*
* class Configuration extends PoIConfiguration {
* Configuration() { this = "Configuration" }
*
* override predicate shown(DataFlow::Node n) { n.getFile().getBaseName() = "server-core.js" }
* }
*
* class RouteHandlerPoI extends ActivePoI {
* RouteHandlerPoI() { this = "RouteHandlerPoI" }
* override predicate is(DataFlow::Node l0) { l0 instanceof Express::RouteHandler }
* }
*
* class RouteSetupAndRouteHandlerPoI extends ActivePoI {
* RouteSetupAndRouteHandlerPoI() { this = "RouteSetupAndRouteHandlerPoI" }
*
* override predicate is(DataFlow::Node l0, DataFlow::Node l1, string t1) {
* l0.asExpr().(Express::RouteSetup).getARouteHandler() = l1 and t1 = "routehandler"
* }
* }
*
* query predicate problems = alertQuery/6;
* ```
*/
import javascript
private import DataFlow
private import filters.ClassifyFiles
private import semmle.javascript.RestrictedLocations
/**
* Provides often used points of interest.
*
* Note that these points of interest should not extend
* `ActivePoI`, and that they can be enabled on
* demand like this:
*
* ```
* class MyPoI extends ServerRelatedPoI, ActivePoI {}
* ```
*/
private module StandardPoIs {
/**
* An unpromoted route setup candidate.
*/
class UnpromotedRouteSetupPoI extends PoI {
UnpromotedRouteSetupPoI() { this = "UnpromotedRouteSetupPoI" }
override predicate is(Node l0) {
l0 instanceof HTTP::RouteSetupCandidate and not l0.asExpr() instanceof HTTP::RouteSetup
}
}
/**
* An unpromoted route handler candidate.
*/
class UnpromotedRouteHandlerPoI extends PoI {
UnpromotedRouteHandlerPoI() { this = "UnpromotedRouteHandlerPoI" }
override predicate is(Node l0) {
l0 instanceof HTTP::RouteHandlerCandidate and not l0 instanceof HTTP::RouteHandler
}
}
/**
* An unpromoted route handler candidate, with explanatory data flow information.
*/
class UnpromotedRouteHandlerWithFlowPoI extends PoI {
UnpromotedRouteHandlerWithFlowPoI() { this = "UnpromotedRouteHandlerWithFlowPoI" }
private DataFlow::SourceNode track(HTTP::RouteHandlerCandidate cand, DataFlow::TypeTracker t) {
t.start() and
result = cand
or
exists(DataFlow::TypeTracker t2 | result = track(cand, t2).track(t2, t))
}
override predicate is(Node l0, Node l1, string t1) {
l0 instanceof HTTP::RouteHandlerCandidate and
not l0 instanceof HTTP::RouteHandler and
l1 = track(l0, TypeTracker::end()) and
(if l1 = l0 then t1 = "ends here" else t1 = "starts/ends here")
}
}
/**
* A callee that is unknown.
*/
class UnknownCalleePoI extends PoI {
UnknownCalleePoI() { this = "UnknownCalleePoI" }
override predicate is(Node l0) {
exists(InvokeNode invk | l0 = invk.getCalleeNode() and not exists(invk.getACallee()))
}
}
/**
* A source of remote flow.
*/
class RemoteFlowSourcePoI extends PoI {
RemoteFlowSourcePoI() { this = "RemoteFlowSourcePoI" }
override predicate is(Node l0) { l0 instanceof RemoteFlowSource }
}
/**
* A "source" for any active configuration.
*/
class SourcePoI extends PoI {
SourcePoI() { this = "SourcePoI" }
override predicate is(Node l0) {
exists(Configuration cfg | cfg.isSource(l0) or cfg.isSource(l0, _))
}
}
/**
* A "sink" for any active configuration.
*/
class SinkPoI extends PoI {
SinkPoI() { this = "SinkPoI" }
override predicate is(Node l0) {
exists(Configuration cfg | cfg.isSink(l0) or cfg.isSink(l0, _))
}
}
/**
* A "barrier" for any active configuration.
*/
class BarrierPoI extends PoI {
BarrierPoI() { this = "BarrierPoI" }
override predicate is(Node l0) {
exists(Configuration cfg |
cfg.isBarrier(l0) or
cfg.isBarrierEdge(l0, _) or
cfg.isBarrierEdge(l0, _, _) or
cfg.isLabeledBarrier(l0, _)
)
}
}
/**
* Provides groups of often used points of interest.
*/
module StandardPoIGroups {
/**
* A server-related point of interest.
*/
class ServerRelatedPoI extends PoI {
ServerRelatedPoI() {
this instanceof UnpromotedRouteSetupPoI or
this instanceof UnpromotedRouteHandlerPoI or
this instanceof UnpromotedRouteHandlerWithFlowPoI
}
}
/**
* A configuration-related point of interest.
*/
class DataFlowConfigurationPoI extends PoI {
DataFlowConfigurationPoI() {
this instanceof SourcePoI or
this instanceof SinkPoI
}
}
}
import StandardPoIGroups
}
import StandardPoIs
/**
* A tagging interface for a custom point of interest that should be
* enabled in the absence of an explicit
* `PoIConfiguration::enabled/1`.
*/
abstract class ActivePoI extends PoI {
bindingset[this]
ActivePoI() { any() }
}
private module PoIConfigDefaults {
predicate enabled(PoI poi) { poi instanceof ActivePoI }
predicate shown(Node n) { not classify(n.getFile(), _) }
}
/**
* A configuration for the points of interest to display.
*/
abstract class PoIConfiguration extends string {
bindingset[this]
PoIConfiguration() { any() }
/**
* Holds if the points of interest from `poi` should be shown.
*/
predicate enabled(PoI poi) { PoIConfigDefaults::enabled(poi) }
/**
* Holds if the points of interest `n` should be shown.
*/
predicate shown(Node n) { PoIConfigDefaults::shown(n) }
}
/**
* A class of points of interest.
*
* Note that only one of the `is/1`, `is/3`, `is/5` methods should
* be overridden, as two overrides will degrade the alert UI
* slightly.
*/
abstract class PoI extends string {
bindingset[this]
PoI() { any() }
/**
* Holds if `l0` is a point of interest.
*/
predicate is(Node l0) { none() }
/**
* Holds if `l0` is a point of interest, with `l1` as an auxiliary location described by `t1`.
*/
predicate is(Node l0, Node l1, string t1) { none() }
/**
* Holds if `l0` is a point of interest, with `l1` and `l2` as auxiliary locations described by `t1` and `t2`.
*/
predicate is(Node l0, Node l1, string t1, Node l2, string t2) { none() }
/**
* Gets the message format for the point of interest.
*/
string getFormat() {
is(_) and result = ""
or
is(_, _, _) and result = "$@"
or
is(_, _, _, _, _) and result = "$@ $@"
}
}
/**
* An alert query for a point of interest.
*
* Should be used as:
*
* ```
* query predicate problems = alertQuery/6;
* ```
*
* Or alternatively:
*
* ```
* from Locatable l1line, string msg, Node l2, string s2, Node l3, string s3
* where alertQuery(l1line, msg, l2, s2, l3, s3)
* select l1line, msg, l2, s2, l3, s3
* ```
*
* Note that some points of interest do not have auxiliary
* locations, so `l2`,`l3`, `s2`, `s3` may have placeholder values.
*/
predicate alertQuery(Locatable l1line, string msg, Node l2, string s2, Node l3, string s3) {
exists(PoI poi, Node l1, string m |
l1.getAstNode().(FirstLineOf) = l1line and
(
not exists(PoIConfiguration cfg) and
PoIConfigDefaults::enabled(poi) and
PoIConfigDefaults::shown(l1)
or
exists(PoIConfiguration cfg |
cfg.enabled(poi) and
cfg.shown(l1)
)
) and
m = poi.getFormat() and
if m = "" then msg = poi else msg = poi + ": " + m
|
poi.is(l1) and
l1 = l2 and
s2 = "irrelevant" and
l1 = l3 and
s3 = "irrelevant"
or
poi.is(l1, l2, s2) and
l1 = l3 and
s3 = "irrelevant"
or
poi.is(l1, l2, s2, l3, s3)
)
}

Просмотреть файл

@ -7,85 +7,8 @@
* @id js/file-classifier
*/
import semmle.javascript.GeneratedCode
import semmle.javascript.frameworks.Testing
import semmle.javascript.frameworks.Templating
import semmle.javascript.dependencies.FrameworkLibraries
/**
* Holds if `e` may be caused by parsing a template file as plain HTML or JavaScript.
*
* We use two heuristics: check for the presence of a known template delimiter preceding
* the error on the same line, and check whether the file name contains `template` or
* `templates`.
*/
predicate maybeCausedByTemplate(JSParseError e) {
exists(File f | f = e.getFile() |
e.getLine().indexOf(Templating::getADelimiter()) <= e.getLocation().getStartColumn()
or
f.getAbsolutePath().regexpMatch("(?i).*\\btemplates?\\b.*")
)
}
/**
* Holds if `e` is an expression in the form `o.p1.p2.p3....pn`.
*/
private predicate isNestedDotExpr(DotExpr e) {
e.getBase() instanceof VarAccess or
isNestedDotExpr(e.getBase())
}
/**
* Holds if `tl` only contains variable declarations and field reads.
*/
private predicate looksLikeExterns(TopLevel tl) {
forex(Stmt s | s.getParent() = tl |
exists(VarDeclStmt vds | vds = s |
forall(VariableDeclarator vd | vd = vds.getADecl() | not exists(vd.getInit()))
)
or
isNestedDotExpr(s.(ExprStmt).getExpr())
)
}
/**
* Holds if `f` is classified as belonging to `category`.
*
* There are currently four categories:
* - `"generated"`: `f` contains generated or minified code;
* - `"test"`: `f` contains test code;
* - `"externs"`: `f` contains externs declarations;
* - `"library"`: `f` contains library code;
* - `"template"`: `f` contains template code.
*/
predicate classify(File f, string category) {
isGenerated(f.getATopLevel()) and category = "generated"
or
(
exists(Test t | t.getFile() = f)
or
exists(string stemExt | stemExt = "test" or stemExt = "spec" |
f = getTestFile(any(File orig), stemExt)
)
or
f.getAbsolutePath().regexpMatch(".*/__(mocks|tests)__/.*")
) and
category = "test"
or
(f.getATopLevel().isExterns() or looksLikeExterns(f.getATopLevel())) and
category = "externs"
or
f.getATopLevel() instanceof FrameworkLibraryInstance and category = "library"
or
exists(JSParseError err | maybeCausedByTemplate(err) |
f = err.getFile() and category = "template"
)
or
// Polymer templates
exists(HTML::Element elt | elt.getName() = "template" |
f = elt.getFile() and category = "template"
)
}
import javascript
import ClassifyFiles
from File f, string category
where classify(f, category)

Просмотреть файл

@ -0,0 +1,85 @@
/**
* Provides classes and predicates for classifying files as containing
* generated code, test code, externs declarations, library code or
* template code.
*/
import semmle.javascript.GeneratedCode
import semmle.javascript.frameworks.Testing
import semmle.javascript.frameworks.Templating
import semmle.javascript.dependencies.FrameworkLibraries
/**
* Holds if `e` may be caused by parsing a template file as plain HTML or JavaScript.
*
* We use two heuristics: check for the presence of a known template delimiter preceding
* the error on the same line, and check whether the file name contains `template` or
* `templates`.
*/
predicate maybeCausedByTemplate(JSParseError e) {
exists(File f | f = e.getFile() |
e.getLine().indexOf(Templating::getADelimiter()) <= e.getLocation().getStartColumn()
or
f.getAbsolutePath().regexpMatch("(?i).*\\btemplates?\\b.*")
)
}
/**
* Holds if `e` is an expression in the form `o.p1.p2.p3....pn`.
*/
private predicate isNestedDotExpr(DotExpr e) {
e.getBase() instanceof VarAccess or
isNestedDotExpr(e.getBase())
}
/**
* Holds if `tl` only contains variable declarations and field reads.
*/
private predicate looksLikeExterns(TopLevel tl) {
forex(Stmt s | s.getParent() = tl |
exists(VarDeclStmt vds | vds = s |
forall(VariableDeclarator vd | vd = vds.getADecl() | not exists(vd.getInit()))
)
or
isNestedDotExpr(s.(ExprStmt).getExpr())
)
}
/**
* Holds if `f` is classified as belonging to `category`.
*
* There are currently four categories:
* - `"generated"`: `f` contains generated or minified code;
* - `"test"`: `f` contains test code;
* - `"externs"`: `f` contains externs declarations;
* - `"library"`: `f` contains library code;
* - `"template"`: `f` contains template code.
*/
predicate classify(File f, string category) {
isGenerated(f.getATopLevel()) and category = "generated"
or
(
exists(Test t | t.getFile() = f)
or
exists(string stemExt | stemExt = "test" or stemExt = "spec" |
f = getTestFile(any(File orig), stemExt)
)
or
f.getAbsolutePath().regexpMatch(".*/__(mocks|tests)__/.*")
) and
category = "test"
or
(f.getATopLevel().isExterns() or looksLikeExterns(f.getATopLevel())) and
category = "externs"
or
f.getATopLevel() instanceof FrameworkLibraryInstance and category = "library"
or
exists(JSParseError err | maybeCausedByTemplate(err) |
f = err.getFile() and category = "template"
)
or
// Polymer templates
exists(HTML::Element elt | elt.getName() = "template" |
f = elt.getFile() and category = "template"
)
}

Просмотреть файл

@ -0,0 +1,4 @@
| tst.js:16:15:16:25 | req.query.x | SourcePoI | tst.js:16:15:16:25 | req.query.x | irrelevant | tst.js:16:15:16:25 | req.query.x | irrelevant |
| tst.js:17:11:17:21 | req.query.x | SinkPoI | tst.js:17:11:17:21 | req.query.x | irrelevant | tst.js:17:11:17:21 | req.query.x | irrelevant |
| tst.js:17:11:17:21 | req.query.x | SourcePoI | tst.js:17:11:17:21 | req.query.x | irrelevant | tst.js:17:11:17:21 | req.query.x | irrelevant |
| tst.js:18:12:18:22 | req.query.x | SourcePoI | tst.js:18:12:18:22 | req.query.x | irrelevant | tst.js:18:12:18:22 | req.query.x | irrelevant |

Просмотреть файл

@ -0,0 +1,13 @@
/**
* @kind problem
*/
import javascript
import experimental.poi.PoI
import semmle.javascript.security.dataflow.CommandInjection
import semmle.javascript.security.dataflow.IndirectCommandInjection
import semmle.javascript.security.dataflow.ShellCommandInjectionFromEnvironment
class MyDataFlowConfigurationPoIs extends DataFlowConfigurationPoI, ActivePoI { }
query predicate problems = alertQuery/6;

Просмотреть файл

@ -0,0 +1,3 @@
| tst.js:6:1:6:16 | (req, res) => 42 | UnpromotedRouteHandlerPoI | tst.js:6:1:6:16 | (req, res) => 42 | irrelevant | tst.js:6:1:6:16 | (req, res) => 42 | irrelevant |
| tst.js:6:1:6:16 | (req, res) => 42 | UnpromotedRouteHandlerWithFlowPoI: $@ | tst.js:6:1:6:16 | (req, res) => 42 | ends here | tst.js:6:1:6:16 | (req, res) => 42 | irrelevant |
| tst.js:13:1:13:36 | otherAp ... h", rh) | UnpromotedRouteSetupPoI | tst.js:13:1:13:36 | otherAp ... h", rh) | irrelevant | tst.js:13:1:13:36 | otherAp ... h", rh) | irrelevant |

Просмотреть файл

@ -0,0 +1,10 @@
/**
* @kind problem
*/
import javascript
import experimental.poi.PoI
class MyServerRelatedPoIs extends ServerRelatedPoI, ActivePoI { }
query predicate problems = alertQuery/6;

Просмотреть файл

@ -0,0 +1,3 @@
| tst.js:6:1:6:16 | (req, res) => 42 | UnpromotedRouteHandlerPoI | tst.js:6:1:6:16 | (req, res) => 42 | irrelevant | tst.js:6:1:6:16 | (req, res) => 42 | irrelevant |
| tst.js:6:1:6:16 | (req, res) => 42 | UnpromotedRouteHandlerWithFlowPoI: $@ | tst.js:6:1:6:16 | (req, res) => 42 | ends here | tst.js:6:1:6:16 | (req, res) => 42 | irrelevant |
| tst.js:13:1:13:36 | otherAp ... h", rh) | UnpromotedRouteSetupPoI | tst.js:13:1:13:36 | otherAp ... h", rh) | irrelevant | tst.js:13:1:13:36 | otherAp ... h", rh) | irrelevant |

Просмотреть файл

@ -0,0 +1,10 @@
/**
* @kind problem
*/
import javascript
import experimental.poi.PoI
class MyServerRelatedPoI extends ServerRelatedPoI, ActivePoI { }
query predicate problems = alertQuery/6;

Просмотреть файл

@ -0,0 +1,6 @@
| tst.js:1:23:1:31 | "express" | SinkPoI | tst.js:1:23:1:31 | "express" | irrelevant | tst.js:1:23:1:31 | "express" | irrelevant |
| tst.js:2:16:2:19 | "fs" | SinkPoI | tst.js:2:16:2:19 | "fs" | irrelevant | tst.js:2:16:2:19 | "fs" | irrelevant |
| tst.js:3:16:3:30 | "child_process" | SinkPoI | tst.js:3:16:3:30 | "child_process" | irrelevant | tst.js:3:16:3:30 | "child_process" | irrelevant |
| tst.js:16:15:16:25 | req.query.x | SourcePoI | tst.js:16:15:16:25 | req.query.x | irrelevant | tst.js:16:15:16:25 | req.query.x | irrelevant |
| tst.js:17:11:17:21 | req.query.x | SourcePoI | tst.js:17:11:17:21 | req.query.x | irrelevant | tst.js:17:11:17:21 | req.query.x | irrelevant |
| tst.js:18:12:18:22 | req.query.x | SourcePoI | tst.js:18:12:18:22 | req.query.x | irrelevant | tst.js:18:12:18:22 | req.query.x | irrelevant |

Просмотреть файл

@ -0,0 +1,11 @@
/**
* @kind problem
*/
import javascript
import experimental.poi.PoI
import semmle.javascript.security.dataflow.TaintedPath
class MyDataflowRelatedPoIs extends DataFlowConfigurationPoI, ActivePoI { }
query predicate problems = alertQuery/6;

Просмотреть файл

@ -0,0 +1,9 @@
| tst.js:8:1:8:44 | app.get ... es) {}) | RouteSetupAndRouterAndRouteHandlerPoI: $@ $@ | tst.js:4:11:4:19 | express() | router | tst.js:8:23:8:43 | functio ... res) {} | routehandler |
| tst.js:8:23:8:43 | functio ... res) {} | RouteHandlerAndSetupPoI: $@ | tst.js:8:1:8:44 | app.get ... es) {}) | setup | tst.js:8:23:8:43 | functio ... res) {} | irrelevant |
| tst.js:8:23:8:43 | functio ... res) {} | RouteHandlerPoI | tst.js:8:23:8:43 | functio ... res) {} | irrelevant | tst.js:8:23:8:43 | functio ... res) {} | irrelevant |
| tst.js:10:10:10:30 | functio ... res) {} | RouteHandlerAndSetupPoI: $@ | tst.js:11:1:11:31 | app.get ... h", rh) | setup | tst.js:10:10:10:30 | functio ... res) {} | irrelevant |
| tst.js:10:10:10:30 | functio ... res) {} | RouteHandlerPoI | tst.js:10:10:10:30 | functio ... res) {} | irrelevant | tst.js:10:10:10:30 | functio ... res) {} | irrelevant |
| tst.js:11:1:11:31 | app.get ... h", rh) | RouteSetupAndRouterAndRouteHandlerPoI: $@ $@ | tst.js:4:11:4:19 | express() | router | tst.js:10:10:10:30 | functio ... res) {} | routehandler |
| tst.js:15:1:19:2 | app.get ... .x);\\n}) | RouteSetupAndRouterAndRouteHandlerPoI: $@ $@ | tst.js:4:11:4:19 | express() | router | tst.js:15:23:19:1 | functio ... y.x);\\n} | routehandler |
| tst.js:15:23:19:1 | functio ... y.x);\\n} | RouteHandlerAndSetupPoI: $@ | tst.js:15:1:19:2 | app.get ... .x);\\n}) | setup | tst.js:15:23:19:1 | functio ... y.x);\\n} | irrelevant |
| tst.js:15:23:19:1 | functio ... y.x);\\n} | RouteHandlerPoI | tst.js:15:23:19:1 | functio ... y.x);\\n} | irrelevant | tst.js:15:23:19:1 | functio ... y.x);\\n} | irrelevant |

Просмотреть файл

@ -0,0 +1,34 @@
/**
* @kind problem
*/
import javascript
import experimental.poi.PoI
import DataFlow
class RouteHandlerPoI extends ActivePoI {
RouteHandlerPoI() { this = "RouteHandlerPoI" }
override predicate is(Node l0) { l0 instanceof Express::RouteHandler }
}
class RouteHandlerAndSetupPoI extends ActivePoI {
RouteHandlerAndSetupPoI() { this = "RouteHandlerAndSetupPoI" }
override predicate is(Node l0, Node l1, string t1) {
l1.asExpr().(Express::RouteSetup).getARouteHandler() = l0 and t1 = "setup"
}
}
class RouteSetupAndRouterAndRouteHandlerPoI extends ActivePoI {
RouteSetupAndRouterAndRouteHandlerPoI() { this = "RouteSetupAndRouterAndRouteHandlerPoI" }
override predicate is(Node l0, Node l1, string t1, Node l2, string t2) {
l0.asExpr().(Express::RouteSetup).getRouter().flow() = l1 and
t1 = "router" and
l0.asExpr().(Express::RouteSetup).getARouteHandler() = l2 and
t2 = "routehandler"
}
}
query predicate problems = alertQuery/6;

Просмотреть файл

@ -0,0 +1 @@
| tst.js:6:1:6:16 | (req, res) => 42 | UnpromotedRouteHandlerPoI | tst.js:6:1:6:16 | (req, res) => 42 | irrelevant | tst.js:6:1:6:16 | (req, res) => 42 | irrelevant |

Просмотреть файл

@ -0,0 +1,10 @@
/**
* @kind problem
*/
import javascript
import experimental.poi.PoI
class MyUnpromotedRouteHandlerPoIs extends UnpromotedRouteHandlerPoI, ActivePoI { }
query predicate problems = alertQuery/6;

Просмотреть файл

@ -0,0 +1,4 @@
| tst.js:16:15:16:25 | req.query.x | SourcePoI | tst.js:16:15:16:25 | req.query.x | irrelevant | tst.js:16:15:16:25 | req.query.x | irrelevant |
| tst.js:17:11:17:21 | req.query.x | SourcePoI | tst.js:17:11:17:21 | req.query.x | irrelevant | tst.js:17:11:17:21 | req.query.x | irrelevant |
| tst.js:18:12:18:22 | req.query.x | SinkPoI | tst.js:18:12:18:22 | req.query.x | irrelevant | tst.js:18:12:18:22 | req.query.x | irrelevant |
| tst.js:18:12:18:22 | req.query.x | SourcePoI | tst.js:18:12:18:22 | req.query.x | irrelevant | tst.js:18:12:18:22 | req.query.x | irrelevant |

Просмотреть файл

@ -0,0 +1,14 @@
/**
* @kind problem
*/
import javascript
import experimental.poi.PoI
import semmle.javascript.security.dataflow.ReflectedXss
import semmle.javascript.security.dataflow.StoredXss
import semmle.javascript.security.dataflow.DomBasedXss
import semmle.javascript.security.dataflow.ExceptionXss
class MyDataFlowConfigurationPoIs extends DataFlowConfigurationPoI, ActivePoI { }
query predicate problems = alertQuery/6;

Просмотреть файл

@ -0,0 +1,19 @@
var express = require("express"),
fs = require("fs"),
cp = require("child_process");
var app = express();
(req, res) => 42;
app.get("/some/path", function(req, res) {});
let rh = function(req, res) {};
app.get("/some/other/path", rh);
otherApp.get("/some/other/path", rh);
app.get("/some/path", function(req, res) {
fs.readFile(req.query.x);
cp.exec(req.query.x);
res.send(req.query.x);
});