" | jquery.js:2:17:2:33 | document.location | jquery.js:7:5:7:34 | "
" | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value |
| jquery.js:8:18:8:34 | "XSS: " + tainted | jquery.js:2:17:2:33 | document.location | jquery.js:8:18:8:34 | "XSS: " + tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value |
@@ -705,7 +733,9 @@ edges
| tst.js:261:11:261:21 | window.name | tst.js:261:11:261:21 | window.name | tst.js:261:11:261:21 | window.name | Cross-site scripting vulnerability due to $@. | tst.js:261:11:261:21 | window.name | user-provided value |
| tst.js:277:22:277:29 | location | tst.js:277:22:277:29 | location | tst.js:277:22:277:29 | location | Cross-site scripting vulnerability due to $@. | tst.js:277:22:277:29 | location | user-provided value |
| tst.js:285:59:285:65 | tainted | tst.js:282:19:282:29 | window.name | tst.js:285:59:285:65 | tainted | Cross-site scripting vulnerability due to $@. | tst.js:282:19:282:29 | window.name | user-provided value |
-| tst.js:297:35:297:42 | location | tst.js:297:35:297:42 | location | tst.js:297:35:297:42 | location | Cross-site scripting vulnerability due to $@. | tst.js:297:35:297:42 | location | user-provided value |
+| tst.js:300:20:300:20 | e | tst.js:298:9:298:16 | location | tst.js:300:20:300:20 | e | Cross-site scripting vulnerability due to $@. | tst.js:298:9:298:16 | location | user-provided value |
+| tst.js:308:20:308:20 | e | tst.js:305:10:305:17 | location | tst.js:308:20:308:20 | e | Cross-site scripting vulnerability due to $@. | tst.js:305:10:305:17 | location | user-provided value |
+| tst.js:313:35:313:42 | location | tst.js:313:35:313:42 | location | tst.js:313:35:313:42 | location | Cross-site scripting vulnerability due to $@. | tst.js:313:35:313:42 | location | user-provided value |
| typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:38 | document.location | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:38 | document.location | user-provided value |
| v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value |
| winjs.js:3:43:3:49 | tainted | winjs.js:2:17:2:33 | document.location | winjs.js:3:43:3:49 | tainted | Cross-site scripting vulnerability due to $@. | winjs.js:2:17:2:33 | document.location | user-provided value |
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/exception-xss.js b/javascript/ql/test/query-tests/Security/CWE-079/exception-xss.js
new file mode 100644
index 00000000000..ac15527209e
--- /dev/null
+++ b/javascript/ql/test/query-tests/Security/CWE-079/exception-xss.js
@@ -0,0 +1,132 @@
+(function() {
+ var foo = document.location;
+
+ function inner(x) {
+ unknown(x);
+ }
+
+ try {
+ unknown(foo);
+ } catch(e) {
+ $('myId').html(e); // NOT OK!
+ }
+
+ try {
+ inner(foo);
+ } catch(e) {
+ $('myId').html(e); // NOT OK!
+ }
+
+ try {
+ unknown(foo + "bar");
+ } catch(e) {
+ $('myId').html(e); // NOT OK!
+ }
+
+ try {
+ unknown({prop: foo});
+ } catch(e) {
+ $('myId').html(e); // We don't flag this for now.
+ }
+
+ try {
+ unknown(["bar", foo]);
+ } catch(e) {
+ $('myId').html(e); // NOT OK!
+ }
+
+ function deep(x) {
+ deep2(x);
+ }
+ function deep2(x) {
+ inner(x);
+ }
+
+ try {
+ deep("bar" + foo);
+ } catch(e) {
+ $('myId').html(e); // NOT OK!
+ }
+
+ try {
+ var tmp = "bar" + foo;
+ } catch(e) {
+ $('myId').html(e); // OK
+ }
+
+ function safe(x) {
+ var foo = x + "bar";
+ }
+
+ try {
+ safe(foo);
+ } catch(e) {
+ $('myId').html(e); // OK
+ }
+
+ try {
+ safe.call(null, foo);
+ } catch(e) {
+ $('myId').html(e); // OK
+ }
+ var myWeirdInner;
+ try {
+ myWeirdInner = function (x) {
+ inner(x);
+ }
+ } catch(e) {
+ $('myId').html(e); // OK
+ }
+ try {
+ myWeirdInner(foo);
+ } catch(e) {
+ $('myId').html(e); // NOT OK!
+ }
+
+ $('myId').html(foo); // Direct leak, reported by other query.
+
+ try {
+ unknown(foo.match(/foo/));
+ } catch(e) {
+ $('myId').html(e); // NOT OK!
+ }
+
+ try {
+ unknown([foo, "bar"]);
+ } catch(e) {
+ $('myId').html(e); // NOT OK!
+ }
+
+ try {
+ try {
+ unknown(foo);
+ } finally {
+ // nothing
+ }
+ } catch(e) {
+ $('myId').html(e); // NOT OK!
+ }
+});
+
+var express = require('express');
+
+var app = express();
+
+app.get('/user/:id', function(req, res) {
+ try {
+ unknown(req.params.id);
+ } catch(e) {
+ res.send("Exception: " + e); // NOT OK!
+ }
+});
+
+
+(function () {
+ sessionStorage.setItem('exceptionSession', document.location.search);
+
+ try {
+ unknown(sessionStorage.getItem('exceptionSession'));
+ } catch(e) {
+ $('myId').html(e); // NOT OK
+ }
+})();
diff --git a/javascript/ql/test/query-tests/Security/CWE-079/tst.js b/javascript/ql/test/query-tests/Security/CWE-079/tst.js
index 780d56e90e1..907f1be9299 100644
--- a/javascript/ql/test/query-tests/Security/CWE-079/tst.js
+++ b/javascript/ql/test/query-tests/Security/CWE-079/tst.js
@@ -293,6 +293,22 @@ function flowThroughPropertyNames() {
$(p); // OK
}
+function basicExceptions() {
+ try {
+ throw location;
+ } catch(e) {
+ $("body").append(e); // NOT OK
+ }
+
+ try {
+ try {
+ throw location
+ } finally {}
+ } catch(e) {
+ $("body").append(e); // NOT OK
+ }
+}
+
function handlebarsSafeString() {
return new Handlebars.SafeString(location); // NOT OK!
}
diff --git a/python/ql/src/Filters/NotGenerated.ql b/python/ql/src/Filters/NotGenerated.ql
index 121fc3c7a45..f74432af66c 100644
--- a/python/ql/src/Filters/NotGenerated.ql
+++ b/python/ql/src/Filters/NotGenerated.ql
@@ -4,6 +4,7 @@
* @kind file-classifier
* @id py/not-generated-file-filter
*/
+import python
import external.DefectFilter
import semmle.python.filters.GeneratedCode
diff --git a/python/ql/src/Filters/NotTest.ql b/python/ql/src/Filters/NotTest.ql
index 4d6b0ec5162..c6d76ae1a7b 100644
--- a/python/ql/src/Filters/NotTest.ql
+++ b/python/ql/src/Filters/NotTest.ql
@@ -4,6 +4,7 @@
* @kind file-classifier
* @id py/not-test-file-filter
*/
+import python
import external.DefectFilter
import semmle.python.filters.Tests
diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql
index 205b477196f..c9fb63ac121 100644
--- a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql
+++ b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql
@@ -11,6 +11,7 @@
* external/cwe/cwe-798
*/
+import python
import semmle.python.security.TaintTracking
import semmle.python.filters.Tests
diff --git a/python/ql/src/external/DuplicateBlock.ql b/python/ql/src/external/DuplicateBlock.ql
index 1a892b87900..7bf1bb6da83 100644
--- a/python/ql/src/external/DuplicateBlock.ql
+++ b/python/ql/src/external/DuplicateBlock.ql
@@ -14,6 +14,7 @@
* @precision medium
* @id py/duplicate-block
*/
+import python
import CodeDuplication
predicate sorted_by_location(DuplicateBlock x, DuplicateBlock y) {
diff --git a/python/ql/src/semmle/python/web/turbogears/Request.qll b/python/ql/src/semmle/python/web/turbogears/Request.qll
index 0003c3dc830..dc7ef63ab56 100644
--- a/python/ql/src/semmle/python/web/turbogears/Request.qll
+++ b/python/ql/src/semmle/python/web/turbogears/Request.qll
@@ -1,21 +1,17 @@
import python
import semmle.python.security.strings.Untrusted
-
import TurboGears
private class ValidatedMethodParameter extends Parameter {
-
ValidatedMethodParameter() {
exists(string name, TurboGearsControllerMethod method |
method.getArgByName(name) = this and
method.getValidationDict().getItem(_).(KeyValuePair).getKey().(StrConst).getText() = name
)
}
-
}
class UnvalidatedControllerMethodParameter extends TaintSource {
-
UnvalidatedControllerMethodParameter() {
exists(Parameter p |
any(TurboGearsControllerMethod m | not m.getName() = "onerror").getAnArg() = p and
@@ -25,9 +21,5 @@ class UnvalidatedControllerMethodParameter extends TaintSource {
)
}
- override predicate isSourceOf(TaintKind kind) {
- kind instanceof UntrustedStringKind
- }
-
+ override predicate isSourceOf(TaintKind kind) { kind instanceof UntrustedStringKind }
}
-
diff --git a/python/ql/src/semmle/python/web/turbogears/Response.qll b/python/ql/src/semmle/python/web/turbogears/Response.qll
index b8640a6fcdd..ddd3d6f711f 100644
--- a/python/ql/src/semmle/python/web/turbogears/Response.qll
+++ b/python/ql/src/semmle/python/web/turbogears/Response.qll
@@ -1,14 +1,10 @@
import python
-
import semmle.python.security.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.Http
import TurboGears
-
-
class ControllerMethodReturnValue extends HttpResponseTaintSink {
-
ControllerMethodReturnValue() {
exists(TurboGearsControllerMethod m |
m.getAReturnValueFlowNode() = this and
@@ -16,14 +12,10 @@ class ControllerMethodReturnValue extends HttpResponseTaintSink {
)
}
- override predicate sinks(TaintKind kind) {
- kind instanceof StringKind
- }
-
+ override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}
class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink {
-
ControllerMethodTemplatedReturnValue() {
exists(TurboGearsControllerMethod m |
m.getAReturnValueFlowNode() = this and
@@ -31,8 +23,5 @@ class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink {
)
}
- override predicate sinks(TaintKind kind) {
- kind instanceof StringDictKind
- }
-
+ override predicate sinks(TaintKind kind) { kind instanceof StringDictKind }
}
diff --git a/python/ql/src/semmle/python/web/turbogears/TurboGears.qll b/python/ql/src/semmle/python/web/turbogears/TurboGears.qll
index c3d417c012e..1cef2f51c84 100644
--- a/python/ql/src/semmle/python/web/turbogears/TurboGears.qll
+++ b/python/ql/src/semmle/python/web/turbogears/TurboGears.qll
@@ -1,55 +1,33 @@
import python
-
import semmle.python.security.TaintTracking
-private ClassObject theTurboGearsControllerClass() {
- result = ModuleObject::named("tg").attr("TGController")
-}
-
-
-ClassObject aTurboGearsControllerClass() {
- result.getASuperType() = theTurboGearsControllerClass()
-}
+private ClassValue theTurboGearsControllerClass() { result = Value::named("tg.TGController") }
+ClassValue aTurboGearsControllerClass() { result.getABaseType+() = theTurboGearsControllerClass() }
class TurboGearsControllerMethod extends Function {
-
ControlFlowNode decorator;
TurboGearsControllerMethod() {
- aTurboGearsControllerClass().getPyClass() = this.getScope() and
+ aTurboGearsControllerClass().getScope() = this.getScope() and
decorator = this.getADecorator().getAFlowNode() and
/* Is decorated with @expose() or @expose(path) */
(
decorator.(CallNode).getFunction().(NameNode).getId() = "expose"
or
- decorator.refersTo(_, ModuleObject::named("tg").attr("expose"), _)
+ decorator.pointsTo().getClass() = Value::named("tg.expose")
)
}
- private ControlFlowNode templateName() {
- result = decorator.(CallNode).getArg(0)
- }
+ private ControlFlowNode templateName() { result = decorator.(CallNode).getArg(0) }
- predicate isTemplated() {
- exists(templateName())
- }
-
- string getTemplateName() {
- exists(StringObject str |
- templateName().refersTo(str) and
- result = str.getText()
- )
- }
+ predicate isTemplated() { exists(templateName()) }
Dict getValidationDict() {
- exists(Call call, Object dict |
+ exists(Call call, Value dict |
call = this.getADecorator() and
call.getFunc().(Name).getId() = "validate" and
- call.getArg(0).refersTo(dict) and
- result = dict.getOrigin()
+ call.getArg(0).pointsTo(dict, result)
)
}
-
}
-
diff --git a/python/ql/test/library-tests/web/turbogears/Controller.expected b/python/ql/test/library-tests/web/turbogears/Controller.expected
index 9b65e8843fa..549934145a0 100644
--- a/python/ql/test/library-tests/web/turbogears/Controller.expected
+++ b/python/ql/test/library-tests/web/turbogears/Controller.expected
@@ -2,3 +2,4 @@
| test.py:13:5:13:50 | Function ok_validated |
| test.py:18:5:18:57 | Function partially_validated |
| test.py:22:5:22:51 | Function not_validated |
+| test.py:26:5:26:28 | Function with_template |
diff --git a/python/ql/test/library-tests/web/turbogears/Sinks.expected b/python/ql/test/library-tests/web/turbogears/Sinks.expected
index 5f2b9b8999f..b528861c340 100644
--- a/python/ql/test/library-tests/web/turbogears/Sinks.expected
+++ b/python/ql/test/library-tests/web/turbogears/Sinks.expected
@@ -2,3 +2,4 @@
| test.py:14 | BinaryExpr | externally controlled string |
| test.py:19 | BinaryExpr | externally controlled string |
| test.py:23 | BinaryExpr | externally controlled string |
+| test.py:27 | Dict | {externally controlled string} |
diff --git a/python/ql/test/library-tests/web/turbogears/test.py b/python/ql/test/library-tests/web/turbogears/test.py
index e4347ee5f6f..bae3a460f43 100644
--- a/python/ql/test/library-tests/web/turbogears/test.py
+++ b/python/ql/test/library-tests/web/turbogears/test.py
@@ -21,3 +21,7 @@ class RootController(TGController):
@expose()
def not_validated(self, a=None, b=None, *args):
return 'Values: %s, %s, %s' % (a, b, args)
+
+ @expose("")
+ def with_template(self):
+ return {'template_var': 'foo'}