Skip to content

Commit c9d77a2

Browse files
authored
Merge pull request #443 from xiemaisi/js/improve-stack-trace-exposure
Approved by asger-semmle
2 parents bf18175 + bdfe938 commit c9d77a2

File tree

4 files changed

+38
-7
lines changed

4 files changed

+38
-7
lines changed

change-notes/1.19/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
| Unused import | Fewer false-positive results | This rule no longer flags imports used by the `transform-react-jsx` Babel plugin. |
4242
| Self assignment | Fewer false-positive results | This rule now ignores self-assignments preceded by a JSDoc comment with a `@type` tag. |
4343
| Client side cross-site scripting | More results | This rule now also flags HTML injection in the body of an email. |
44+
| Information exposure through a stack trace | More results | This rule now also flags cases where the entire exception object (including the stack trace) may be exposed. |
4445

4546
## Changes to QL libraries
4647

javascript/ql/src/semmle/javascript/security/dataflow/StackTraceExposure.qll

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,32 @@ module StackTraceExposure {
2323
src instanceof Source
2424
}
2525

26+
override predicate isSanitizer(DataFlow::Node nd) {
27+
super.isSanitizer(nd)
28+
or
29+
// read of a property other than `stack`
30+
nd.(DataFlow::PropRead).getPropertyName() != "stack"
31+
or
32+
// `toString` does not include the stack trace
33+
nd.(DataFlow::MethodCallNode).getMethodName() = "toString"
34+
or
35+
nd = StringConcatenation::getAnOperand(_)
36+
}
37+
2638
override predicate isSink(DataFlow::Node snk) {
2739
snk instanceof Sink
2840
}
2941
}
3042

43+
3144
/**
3245
* A read of the `stack` property of an exception, viewed as a data flow
3346
* sink for stack trace exposure vulnerabilities.
3447
*/
35-
class DefaultSource extends Source, DataFlow::ValueNode {
48+
class DefaultSource extends Source, DataFlow::Node {
3649
DefaultSource() {
37-
// any read of the `stack` property of an exception is a source
38-
exists (Parameter exc |
39-
exc = any(TryStmt try).getACatchClause().getAParameter() and
40-
this = DataFlow::parameterNode(exc).getAPropertyRead("stack")
41-
)
50+
// any exception is a source
51+
this = DataFlow::parameterNode(any(TryStmt try).getACatchClause().getAParameter())
4252
}
4353
}
4454

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
| node.js:11:13:11:21 | err.stack | Stack trace information from $@ may be exposed to an external user here. | node.js:11:13:11:21 | err.stack | here |
1+
| node.js:11:13:11:21 | err.stack | Stack trace information from $@ may be exposed to an external user here. | node.js:8:10:8:12 | err | here |
2+
| tst.js:7:13:7:13 | e | Stack trace information from $@ may be exposed to an external user here. | tst.js:6:12:6:12 | e | here |
3+
| tst.js:17:11:17:17 | e.stack | Stack trace information from $@ may be exposed to an external user here. | tst.js:6:12:6:12 | e | here |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
var http = require('http');
2+
3+
http.createServer(function onRequest(req, res) {
4+
try {
5+
throw new Error();
6+
} catch (e) {
7+
res.end(e); // NOT OK
8+
fail(res, e);
9+
res.end(e.message); // OK
10+
res.end("Caught exception " + e); // OK
11+
res.end(e.toString()); // OK
12+
res.end(`Caught exception ${e}.`); // OK
13+
}
14+
});
15+
16+
function fail(res, e) {
17+
res.end(e.stack); // NOT OK
18+
}

0 commit comments

Comments
 (0)