mirror of
https://github.com/github/codeql.git
synced 2026-05-02 20:25:13 +02:00
@@ -0,0 +1,45 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Directly using user-controlled objects as arguments to template engines might allow an attacker to do
|
||||
local file reads or even remote code execution.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Avoid using user-controlled objects as arguments to a template engine. Instead, construct the object explicitly with
|
||||
the specific properties needed by the template.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
In the example below a server uses the user-controlled <code>profile</code> object to
|
||||
render the <code>index</code> template.
|
||||
</p>
|
||||
<sample src="examples/TemplateObjectInjection.js" />
|
||||
<p>
|
||||
However, if an attacker adds a <code>layout</code> property to the <code>profile</code> object then
|
||||
the server will load the file specified by the <code>layout</code> property, thereby allowing an attacker
|
||||
to do local file reads.
|
||||
</p>
|
||||
<p>
|
||||
The fix is to have the server construct the object, and only add the properties that are needed by the template.
|
||||
</p>
|
||||
<sample src="examples/TemplateObjectInjection_fixed.js" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
blog.shoebpatel.com: <a href="https://blog.shoebpatel.com/2021/01/23/The-Secret-Parameter-LFR-and-Potential-RCE-in-NodeJS-Apps/">The Secret Parameter, LFR, and Potential RCE in NodeJS Apps</a>.
|
||||
</li>
|
||||
<li>
|
||||
cwe.mitre.org: <a href="https://cwe.mitre.org/data/definitions/73.html">CWE-73: External Control of File Name or Path</a>
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @name Template Object Injection
|
||||
* @description Instantiating a template using a user-controlled object is vulnerable to local file read and potential remote code execution.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id js/template-object-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-073
|
||||
* external/cwe/cwe-094
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import DataFlow::PathGraph
|
||||
import semmle.javascript.security.dataflow.TemplateObjectInjection::TemplateObjectInjection
|
||||
|
||||
from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Template object injection due to $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
@@ -0,0 +1,7 @@
|
||||
var app = require('express')();
|
||||
app.set('view engine', 'hbs');
|
||||
|
||||
app.post('/', function (req, res, next) {
|
||||
var profile = req.body.profile;
|
||||
res.render('index', profile);
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
var app = require('express')();
|
||||
app.set('view engine', 'hbs');
|
||||
|
||||
app.post('/', function (req, res, next) {
|
||||
var profile = req.body.profile;
|
||||
res.render('index', {
|
||||
name: profile.name,
|
||||
location: profile.location
|
||||
});
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* @name Template Object Injection
|
||||
* @description Instantiating a template using a user-controlled object is vulnerable to local file read and potential remote code execution.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id js/template-object-injection
|
||||
* @tags security
|
||||
* external/cwe/cwe-073
|
||||
* external/cwe/cwe-094
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import DataFlow::PathGraph
|
||||
import semmle.javascript.security.TaintedObject
|
||||
|
||||
class TemplateObjInjectionConfig extends TaintTracking::Configuration {
|
||||
TemplateObjInjectionConfig() { this = "TemplateObjInjectionConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
|
||||
TaintedObject::isSource(source, label)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
|
||||
label = TaintedObject::label() and
|
||||
exists(MethodCallExpr mc |
|
||||
Express::isResponse(mc.getReceiver()) and
|
||||
mc.getMethodName() = "render" and
|
||||
sink.asExpr() = mc.getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
guard instanceof TaintedObject::SanitizerGuard
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node src, DataFlow::Node trg, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl
|
||||
) {
|
||||
TaintedObject::step(src, trg, inlbl, outlbl)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Template object injection due to $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
@@ -1,10 +0,0 @@
|
||||
var app = require('express')();
|
||||
app.set('view engine', 'hbs');
|
||||
|
||||
app.post('/path', function(req, res) {
|
||||
var bodyParameter = req.body.bodyParameter
|
||||
var queryParameter = req.query.queryParameter
|
||||
|
||||
res.render('template', bodyParameter)
|
||||
res.render('template', queryParameter)
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
var app = require('express')();
|
||||
app.set('view engine', 'hbs');
|
||||
|
||||
app.post('/path', function(req, res) {
|
||||
var bodyParameter = req.body.bodyParameter
|
||||
var queryParameter = req.query.queryParameter
|
||||
|
||||
res.render('template', {bodyParameter})
|
||||
res.render('template', {queryParameter})
|
||||
});
|
||||
@@ -738,16 +738,32 @@ module Express {
|
||||
* as the value of a template variable.
|
||||
*/
|
||||
private class TemplateInput extends HTTP::ResponseBody {
|
||||
RouteHandler rh;
|
||||
TemplateObjectInput obj;
|
||||
|
||||
TemplateInput() {
|
||||
obj.getALocalSource().(DataFlow::ObjectLiteralNode).hasPropertyWrite(_, this.flow())
|
||||
}
|
||||
|
||||
override RouteHandler getRouteHandler() { result = obj.getRouteHandler() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An object passed to the `render` method of an HTTP response object.
|
||||
*/
|
||||
class TemplateObjectInput extends DataFlow::Node {
|
||||
RouteHandler rh;
|
||||
|
||||
TemplateObjectInput() {
|
||||
exists(DataFlow::MethodCallNode render |
|
||||
render.calls(rh.getAResponseExpr().flow(), "render") and
|
||||
this = render.getOptionArgument(1, _).asExpr()
|
||||
this = render.getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
override RouteHandler getRouteHandler() { result = rh }
|
||||
/**
|
||||
* Gets the route handler that uses this object.
|
||||
*/
|
||||
RouteHandler getRouteHandler() { result = rh }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for reasoning about
|
||||
* template object injection vulnerabilities.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `TemplateObjectInjection::Configuration` is needed, otherwise
|
||||
* `TemplateObjectInjectionCustomizations` should be imported instead.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* Provides a taint tracking configuration for reasoning template object injection vulnerabilities.
|
||||
*/
|
||||
module TemplateObjectInjection {
|
||||
import TemplateObjectInjectionCustomizations::TemplateObjectInjection
|
||||
private import semmle.javascript.security.TaintedObject
|
||||
|
||||
/**
|
||||
* A taint tracking configuration for reasoning about template object injection vulnerabilities.
|
||||
*/
|
||||
class TemplateObjInjectionConfig extends TaintTracking::Configuration {
|
||||
TemplateObjInjectionConfig() { this = "TemplateObjInjectionConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
|
||||
source.(Source).getAFlowLabel() = label
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
|
||||
sink instanceof Sink and label = TaintedObject::label()
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
guard instanceof TaintedObject::SanitizerGuard
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node src, DataFlow::Node trg, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl
|
||||
) {
|
||||
TaintedObject::step(src, trg, inlbl, outlbl)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* template object injection vulnerabilities, as well as extension points for
|
||||
* adding your own.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.security.TaintedObjectCustomizations
|
||||
|
||||
/**
|
||||
* Provides sources, sinks and sanitizers for reasoning about
|
||||
* template object injection vulnerabilities.
|
||||
*/
|
||||
module TemplateObjectInjection {
|
||||
/**
|
||||
* A data flow source for template object injection vulnerabilities.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node {
|
||||
/** Gets a flow label to associate with this source. */
|
||||
abstract DataFlow::FlowLabel getAFlowLabel();
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow sink for template object injection vulnerabilities.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for template object injection vulnerabilities.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
private class TaintedObjectSourceAsSource extends Source {
|
||||
TaintedObjectSourceAsSource() { this instanceof TaintedObject::Source }
|
||||
|
||||
override DataFlow::FlowLabel getAFlowLabel() { result = TaintedObject::label() }
|
||||
}
|
||||
|
||||
private class RemoteFlowSourceAsSource extends Source {
|
||||
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
|
||||
|
||||
override DataFlow::FlowLabel getAFlowLabel() { result.isTaint() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An argument given to the `render` method on an Express response object,
|
||||
* where the view engine used by the Express instance is vulnerable to template object injection.
|
||||
*/
|
||||
private class TemplateSink extends Sink, Express::TemplateObjectInput {
|
||||
TemplateSink() {
|
||||
exists(
|
||||
Express::RouteSetup setup, Express::RouterDefinition router, Express::RouterDefinition top
|
||||
|
|
||||
setup.getARouteHandler() = getRouteHandler() and
|
||||
setup.getRouter() = router and
|
||||
top.getASubRouter*() = router and
|
||||
usesVulnerableTemplateEngine(top)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the package name for a templating library that is vulnerable to template object injection.
|
||||
*/
|
||||
private string getAVulnerableTemplateEngine() {
|
||||
result =
|
||||
[
|
||||
"eta", "squirrelly", "haml-coffee", "express-hbs", "ejs", "hbs", "whiskers",
|
||||
"express-handlebars"
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the "view engine" of `router` is set to a vulnerable templating engine.
|
||||
*/
|
||||
predicate usesVulnerableTemplateEngine(Express::RouterDefinition router) {
|
||||
// option 1: `app.set("view engine", "theEngine")`.
|
||||
// Express will load the engine automatically.
|
||||
exists(MethodCallExpr call |
|
||||
router.flowsTo(call.getReceiver()) and
|
||||
call.getMethodName() = "set" and
|
||||
call.getArgument(0).getStringValue() = "view engine" and
|
||||
call.getArgument(1).getStringValue() = getAVulnerableTemplateEngine()
|
||||
)
|
||||
or
|
||||
// option 2: setup an engine.
|
||||
// ```app.engine("name", engine); app.set("view engine", "name");```
|
||||
// ^^^ `registerCall` ^^^ ^^^ `viewEngineCall` ^^^
|
||||
exists(
|
||||
DataFlow::MethodCallNode registerCall, DataFlow::SourceNode engine,
|
||||
DataFlow::MethodCallNode viewEngineCall
|
||||
|
|
||||
// `app.engine("name", engine)
|
||||
router.flowsTo(registerCall.getReceiver().asExpr()) and
|
||||
registerCall.getMethodName() = ["engine", "register"] and
|
||||
engine = registerCall.getArgument(1).getALocalSource() and
|
||||
// app.set("view engine", "name")
|
||||
router.flowsTo(viewEngineCall.getReceiver().asExpr()) and
|
||||
viewEngineCall.getMethodName() = "set" and
|
||||
viewEngineCall.getArgument(0).getStringValue() = "view engine" and
|
||||
// The name set by the `app.engine("name")` call matches `app.set("view engine", "name")`.
|
||||
(
|
||||
viewEngineCall.getArgument(1).getStringValue() =
|
||||
registerCall.getArgument(0).getStringValue()
|
||||
or
|
||||
"." + viewEngineCall.getArgument(1).getStringValue() =
|
||||
registerCall.getArgument(0).getStringValue()
|
||||
)
|
||||
|
|
||||
// Different ways of initializing vulnerable template engines.
|
||||
engine = DataFlow::moduleImport(getAVulnerableTemplateEngine())
|
||||
or
|
||||
engine = DataFlow::moduleImport(getAVulnerableTemplateEngine()).getAPropertyRead("__express")
|
||||
or
|
||||
engine = DataFlow::moduleImport("express-handlebars").getACall()
|
||||
or
|
||||
engine = DataFlow::moduleImport("express-handlebars").getAPropertyRead("engine")
|
||||
or
|
||||
exists(DataFlow::SourceNode hbs |
|
||||
hbs = DataFlow::moduleImport("express-hbs")
|
||||
or
|
||||
hbs = DataFlow::moduleImport("express-hbs").getAMemberCall("create")
|
||||
|
|
||||
engine = hbs.getAMemberCall(["express3", "express4"])
|
||||
)
|
||||
or
|
||||
engine =
|
||||
DataFlow::moduleImport("consolidate").getAPropertyRead(getAVulnerableTemplateEngine())
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
nodes
|
||||
| tst.js:5:9:5:46 | bodyParameter |
|
||||
| tst.js:5:25:5:32 | req.body |
|
||||
| tst.js:5:25:5:32 | req.body |
|
||||
| tst.js:5:25:5:46 | req.bod ... rameter |
|
||||
| tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter |
|
||||
| tst.js:8:28:8:40 | bodyParameter |
|
||||
| tst.js:8:28:8:40 | bodyParameter |
|
||||
| tst.js:9:28:9:41 | queryParameter |
|
||||
| tst.js:9:28:9:41 | queryParameter |
|
||||
| tst.js:18:19:18:32 | queryParameter |
|
||||
| tst.js:18:19:18:32 | queryParameter |
|
||||
| tst.js:21:24:21:26 | obj |
|
||||
| tst.js:21:24:21:26 | obj |
|
||||
| tst.js:22:28:22:30 | obj |
|
||||
| tst.js:22:28:22:30 | obj |
|
||||
| tst.js:24:11:24:24 | str |
|
||||
| tst.js:24:17:24:19 | obj |
|
||||
| tst.js:24:17:24:24 | obj + "" |
|
||||
| tst.js:27:28:27:42 | JSON.parse(str) |
|
||||
| tst.js:27:28:27:42 | JSON.parse(str) |
|
||||
| tst.js:27:39:27:41 | str |
|
||||
edges
|
||||
| tst.js:5:9:5:46 | bodyParameter | tst.js:8:28:8:40 | bodyParameter |
|
||||
| tst.js:5:9:5:46 | bodyParameter | tst.js:8:28:8:40 | bodyParameter |
|
||||
| tst.js:5:25:5:32 | req.body | tst.js:5:25:5:46 | req.bod ... rameter |
|
||||
| tst.js:5:25:5:32 | req.body | tst.js:5:25:5:46 | req.bod ... rameter |
|
||||
| tst.js:5:25:5:46 | req.bod ... rameter | tst.js:5:9:5:46 | bodyParameter |
|
||||
| tst.js:6:9:6:49 | queryParameter | tst.js:9:28:9:41 | queryParameter |
|
||||
| tst.js:6:9:6:49 | queryParameter | tst.js:9:28:9:41 | queryParameter |
|
||||
| tst.js:6:9:6:49 | queryParameter | tst.js:18:19:18:32 | queryParameter |
|
||||
| tst.js:6:9:6:49 | queryParameter | tst.js:18:19:18:32 | queryParameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:18:19:18:32 | queryParameter | tst.js:21:24:21:26 | obj |
|
||||
| tst.js:18:19:18:32 | queryParameter | tst.js:21:24:21:26 | obj |
|
||||
| tst.js:21:24:21:26 | obj | tst.js:22:28:22:30 | obj |
|
||||
| tst.js:21:24:21:26 | obj | tst.js:22:28:22:30 | obj |
|
||||
| tst.js:21:24:21:26 | obj | tst.js:24:17:24:19 | obj |
|
||||
| tst.js:24:11:24:24 | str | tst.js:27:39:27:41 | str |
|
||||
| tst.js:24:17:24:19 | obj | tst.js:24:17:24:24 | obj + "" |
|
||||
| tst.js:24:17:24:24 | obj + "" | tst.js:24:11:24:24 | str |
|
||||
| tst.js:27:39:27:41 | str | tst.js:27:28:27:42 | JSON.parse(str) |
|
||||
| tst.js:27:39:27:41 | str | tst.js:27:28:27:42 | JSON.parse(str) |
|
||||
#select
|
||||
| tst.js:8:28:8:40 | bodyParameter | tst.js:5:25:5:32 | req.body | tst.js:8:28:8:40 | bodyParameter | Template object injection due to $@. | tst.js:5:25:5:32 | req.body | user-provided value |
|
||||
| tst.js:9:28:9:41 | queryParameter | tst.js:6:26:6:49 | req.que ... rameter | tst.js:9:28:9:41 | queryParameter | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value |
|
||||
| tst.js:22:28:22:30 | obj | tst.js:6:26:6:49 | req.que ... rameter | tst.js:22:28:22:30 | obj | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value |
|
||||
| tst.js:27:28:27:42 | JSON.parse(str) | tst.js:6:26:6:49 | req.que ... rameter | tst.js:27:28:27:42 | JSON.parse(str) | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE-073/TemplateObjectInjection.ql
|
||||
@@ -0,0 +1,115 @@
|
||||
nodes
|
||||
| tst2.js:6:9:6:46 | bodyParameter |
|
||||
| tst2.js:6:25:6:32 | req.body |
|
||||
| tst2.js:6:25:6:32 | req.body |
|
||||
| tst2.js:6:25:6:46 | req.bod ... rameter |
|
||||
| tst2.js:7:28:7:40 | bodyParameter |
|
||||
| tst2.js:7:28:7:40 | bodyParameter |
|
||||
| tst2.js:26:9:26:46 | bodyParameter |
|
||||
| tst2.js:26:25:26:32 | req.body |
|
||||
| tst2.js:26:25:26:32 | req.body |
|
||||
| tst2.js:26:25:26:46 | req.bod ... rameter |
|
||||
| tst2.js:27:28:27:40 | bodyParameter |
|
||||
| tst2.js:27:28:27:40 | bodyParameter |
|
||||
| tst2.js:34:9:34:46 | bodyParameter |
|
||||
| tst2.js:34:25:34:32 | req.body |
|
||||
| tst2.js:34:25:34:32 | req.body |
|
||||
| tst2.js:34:25:34:46 | req.bod ... rameter |
|
||||
| tst2.js:35:28:35:40 | bodyParameter |
|
||||
| tst2.js:35:28:35:40 | bodyParameter |
|
||||
| tst2.js:42:9:42:46 | bodyParameter |
|
||||
| tst2.js:42:25:42:32 | req.body |
|
||||
| tst2.js:42:25:42:32 | req.body |
|
||||
| tst2.js:42:25:42:46 | req.bod ... rameter |
|
||||
| tst2.js:43:28:43:40 | bodyParameter |
|
||||
| tst2.js:43:28:43:40 | bodyParameter |
|
||||
| tst2.js:51:9:51:46 | bodyParameter |
|
||||
| tst2.js:51:25:51:32 | req.body |
|
||||
| tst2.js:51:25:51:32 | req.body |
|
||||
| tst2.js:51:25:51:46 | req.bod ... rameter |
|
||||
| tst2.js:52:28:52:40 | bodyParameter |
|
||||
| tst2.js:52:28:52:40 | bodyParameter |
|
||||
| tst.js:5:9:5:46 | bodyParameter |
|
||||
| tst.js:5:25:5:32 | req.body |
|
||||
| tst.js:5:25:5:32 | req.body |
|
||||
| tst.js:5:25:5:46 | req.bod ... rameter |
|
||||
| tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter |
|
||||
| tst.js:8:28:8:40 | bodyParameter |
|
||||
| tst.js:8:28:8:40 | bodyParameter |
|
||||
| tst.js:9:28:9:41 | queryParameter |
|
||||
| tst.js:9:28:9:41 | queryParameter |
|
||||
| tst.js:18:19:18:32 | queryParameter |
|
||||
| tst.js:18:19:18:32 | queryParameter |
|
||||
| tst.js:21:24:21:26 | obj |
|
||||
| tst.js:21:24:21:26 | obj |
|
||||
| tst.js:22:28:22:30 | obj |
|
||||
| tst.js:22:28:22:30 | obj |
|
||||
| tst.js:24:11:24:24 | str |
|
||||
| tst.js:24:17:24:19 | obj |
|
||||
| tst.js:24:17:24:24 | obj + "" |
|
||||
| tst.js:27:28:27:42 | JSON.parse(str) |
|
||||
| tst.js:27:28:27:42 | JSON.parse(str) |
|
||||
| tst.js:27:39:27:41 | str |
|
||||
edges
|
||||
| tst2.js:6:9:6:46 | bodyParameter | tst2.js:7:28:7:40 | bodyParameter |
|
||||
| tst2.js:6:9:6:46 | bodyParameter | tst2.js:7:28:7:40 | bodyParameter |
|
||||
| tst2.js:6:25:6:32 | req.body | tst2.js:6:25:6:46 | req.bod ... rameter |
|
||||
| tst2.js:6:25:6:32 | req.body | tst2.js:6:25:6:46 | req.bod ... rameter |
|
||||
| tst2.js:6:25:6:46 | req.bod ... rameter | tst2.js:6:9:6:46 | bodyParameter |
|
||||
| tst2.js:26:9:26:46 | bodyParameter | tst2.js:27:28:27:40 | bodyParameter |
|
||||
| tst2.js:26:9:26:46 | bodyParameter | tst2.js:27:28:27:40 | bodyParameter |
|
||||
| tst2.js:26:25:26:32 | req.body | tst2.js:26:25:26:46 | req.bod ... rameter |
|
||||
| tst2.js:26:25:26:32 | req.body | tst2.js:26:25:26:46 | req.bod ... rameter |
|
||||
| tst2.js:26:25:26:46 | req.bod ... rameter | tst2.js:26:9:26:46 | bodyParameter |
|
||||
| tst2.js:34:9:34:46 | bodyParameter | tst2.js:35:28:35:40 | bodyParameter |
|
||||
| tst2.js:34:9:34:46 | bodyParameter | tst2.js:35:28:35:40 | bodyParameter |
|
||||
| tst2.js:34:25:34:32 | req.body | tst2.js:34:25:34:46 | req.bod ... rameter |
|
||||
| tst2.js:34:25:34:32 | req.body | tst2.js:34:25:34:46 | req.bod ... rameter |
|
||||
| tst2.js:34:25:34:46 | req.bod ... rameter | tst2.js:34:9:34:46 | bodyParameter |
|
||||
| tst2.js:42:9:42:46 | bodyParameter | tst2.js:43:28:43:40 | bodyParameter |
|
||||
| tst2.js:42:9:42:46 | bodyParameter | tst2.js:43:28:43:40 | bodyParameter |
|
||||
| tst2.js:42:25:42:32 | req.body | tst2.js:42:25:42:46 | req.bod ... rameter |
|
||||
| tst2.js:42:25:42:32 | req.body | tst2.js:42:25:42:46 | req.bod ... rameter |
|
||||
| tst2.js:42:25:42:46 | req.bod ... rameter | tst2.js:42:9:42:46 | bodyParameter |
|
||||
| tst2.js:51:9:51:46 | bodyParameter | tst2.js:52:28:52:40 | bodyParameter |
|
||||
| tst2.js:51:9:51:46 | bodyParameter | tst2.js:52:28:52:40 | bodyParameter |
|
||||
| tst2.js:51:25:51:32 | req.body | tst2.js:51:25:51:46 | req.bod ... rameter |
|
||||
| tst2.js:51:25:51:32 | req.body | tst2.js:51:25:51:46 | req.bod ... rameter |
|
||||
| tst2.js:51:25:51:46 | req.bod ... rameter | tst2.js:51:9:51:46 | bodyParameter |
|
||||
| tst.js:5:9:5:46 | bodyParameter | tst.js:8:28:8:40 | bodyParameter |
|
||||
| tst.js:5:9:5:46 | bodyParameter | tst.js:8:28:8:40 | bodyParameter |
|
||||
| tst.js:5:25:5:32 | req.body | tst.js:5:25:5:46 | req.bod ... rameter |
|
||||
| tst.js:5:25:5:32 | req.body | tst.js:5:25:5:46 | req.bod ... rameter |
|
||||
| tst.js:5:25:5:46 | req.bod ... rameter | tst.js:5:9:5:46 | bodyParameter |
|
||||
| tst.js:6:9:6:49 | queryParameter | tst.js:9:28:9:41 | queryParameter |
|
||||
| tst.js:6:9:6:49 | queryParameter | tst.js:9:28:9:41 | queryParameter |
|
||||
| tst.js:6:9:6:49 | queryParameter | tst.js:18:19:18:32 | queryParameter |
|
||||
| tst.js:6:9:6:49 | queryParameter | tst.js:18:19:18:32 | queryParameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter |
|
||||
| tst.js:18:19:18:32 | queryParameter | tst.js:21:24:21:26 | obj |
|
||||
| tst.js:18:19:18:32 | queryParameter | tst.js:21:24:21:26 | obj |
|
||||
| tst.js:21:24:21:26 | obj | tst.js:22:28:22:30 | obj |
|
||||
| tst.js:21:24:21:26 | obj | tst.js:22:28:22:30 | obj |
|
||||
| tst.js:21:24:21:26 | obj | tst.js:24:17:24:19 | obj |
|
||||
| tst.js:24:11:24:24 | str | tst.js:27:39:27:41 | str |
|
||||
| tst.js:24:17:24:19 | obj | tst.js:24:17:24:24 | obj + "" |
|
||||
| tst.js:24:17:24:24 | obj + "" | tst.js:24:11:24:24 | str |
|
||||
| tst.js:27:39:27:41 | str | tst.js:27:28:27:42 | JSON.parse(str) |
|
||||
| tst.js:27:39:27:41 | str | tst.js:27:28:27:42 | JSON.parse(str) |
|
||||
#select
|
||||
| tst2.js:7:28:7:40 | bodyParameter | tst2.js:6:25:6:32 | req.body | tst2.js:7:28:7:40 | bodyParameter | Template object injection due to $@. | tst2.js:6:25:6:32 | req.body | user-provided value |
|
||||
| tst2.js:27:28:27:40 | bodyParameter | tst2.js:26:25:26:32 | req.body | tst2.js:27:28:27:40 | bodyParameter | Template object injection due to $@. | tst2.js:26:25:26:32 | req.body | user-provided value |
|
||||
| tst2.js:35:28:35:40 | bodyParameter | tst2.js:34:25:34:32 | req.body | tst2.js:35:28:35:40 | bodyParameter | Template object injection due to $@. | tst2.js:34:25:34:32 | req.body | user-provided value |
|
||||
| tst2.js:43:28:43:40 | bodyParameter | tst2.js:42:25:42:32 | req.body | tst2.js:43:28:43:40 | bodyParameter | Template object injection due to $@. | tst2.js:42:25:42:32 | req.body | user-provided value |
|
||||
| tst2.js:52:28:52:40 | bodyParameter | tst2.js:51:25:51:32 | req.body | tst2.js:52:28:52:40 | bodyParameter | Template object injection due to $@. | tst2.js:51:25:51:32 | req.body | user-provided value |
|
||||
| tst.js:8:28:8:40 | bodyParameter | tst.js:5:25:5:32 | req.body | tst.js:8:28:8:40 | bodyParameter | Template object injection due to $@. | tst.js:5:25:5:32 | req.body | user-provided value |
|
||||
| tst.js:9:28:9:41 | queryParameter | tst.js:6:26:6:49 | req.que ... rameter | tst.js:9:28:9:41 | queryParameter | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value |
|
||||
| tst.js:22:28:22:30 | obj | tst.js:6:26:6:49 | req.que ... rameter | tst.js:22:28:22:30 | obj | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value |
|
||||
| tst.js:27:28:27:42 | JSON.parse(str) | tst.js:6:26:6:49 | req.que ... rameter | tst.js:27:28:27:42 | JSON.parse(str) | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-073/TemplateObjectInjection.ql
|
||||
54
javascript/ql/test/query-tests/Security/CWE-073/tst2.js
Normal file
54
javascript/ql/test/query-tests/Security/CWE-073/tst2.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const handlebars = require("express-handlebars");
|
||||
var app = require('express')();
|
||||
app.engine( '.hbs', handlebars({ defaultLayout: 'main', extname: '.hbs' }) );
|
||||
app.set('view engine', '.hbs')
|
||||
app.post('/path', function(req, res) {
|
||||
var bodyParameter = req.body.bodyParameter;
|
||||
res.render('template', bodyParameter); // NOT OK
|
||||
});
|
||||
|
||||
var app2 = require('express')();
|
||||
app2.post('/path', function(req, res) {
|
||||
var bodyParameter = req.body.bodyParameter;
|
||||
res.render('template', bodyParameter); // OK
|
||||
});
|
||||
|
||||
var app3 = require('express')();
|
||||
app3.set('view engine', 'pug');
|
||||
app3.post('/path', function(req, res) {
|
||||
var bodyParameter = req.body.bodyParameter;
|
||||
res.render('template', bodyParameter); // OK
|
||||
});
|
||||
|
||||
var app4 = require('express')();
|
||||
app4.set('view engine', 'ejs');
|
||||
app4.post('/path', function(req, res) {
|
||||
var bodyParameter = req.body.bodyParameter;
|
||||
res.render('template', bodyParameter); // NOT OK
|
||||
});
|
||||
|
||||
var app5 = require('express')();
|
||||
app5.engine("foobar", require("consolidate").whiskers);
|
||||
app5.set('view engine', 'foobar');
|
||||
app5.post('/path', function(req, res) {
|
||||
var bodyParameter = req.body.bodyParameter;
|
||||
res.render('template', bodyParameter); // NOT OK
|
||||
});
|
||||
|
||||
var app6 = require('express')();
|
||||
app6.register(".html", require("consolidate").whiskers);
|
||||
app6.set('view engine', 'html');
|
||||
app6.post('/path', function(req, res) {
|
||||
var bodyParameter = req.body.bodyParameter;
|
||||
res.render('template', bodyParameter); // NOT OK
|
||||
});
|
||||
|
||||
const express = require('express');
|
||||
var router = express.Router();
|
||||
var app7 = express();
|
||||
app7.set('view engine', 'ejs');
|
||||
router.post('/path', function(req, res) {
|
||||
var bodyParameter = req.body.bodyParameter;
|
||||
res.render('template', bodyParameter); // NOT OK
|
||||
});
|
||||
app7.use("/router", router);
|
||||
Reference in New Issue
Block a user