Skip to content

Commit e8b05b7

Browse files
committed
Added support for detecting unsafe methods used for origin verification
1 parent cf3142e commit e8b05b7

1 file changed

Lines changed: 34 additions & 33 deletions

File tree

javascript/ql/src/experimental/Security/CWE-020/PostMessageNoOriginCheck.ql

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,59 +12,60 @@
1212
*/
1313

1414
import javascript
15+
import semmle.javascript.security.dataflow.DOM
1516

1617
/**
17-
* A call to a `window` event listener
18+
* A method call for the insecure functions used to verify the `MessageEvent.origin`.
1819
*/
19-
class WindowListeners extends DataFlow::CallNode {
20-
WindowListeners() {
21-
exists(DataFlow::SourceNode source |
22-
source = DataFlow::globalVarRef("window") and
23-
this = source.getAMethodCall("addEventListener")
20+
class InsufficientOriginChecks extends DataFlow::MethodCallNode {
21+
InsufficientOriginChecks() {
22+
exists(string name | name = getMethodName() |
23+
name = "indexOf" or
24+
name = "includes" or
25+
name = "endsWith" or
26+
name = "startsWith" or
27+
name = "lastIndexOf"
2428
)
2529
}
2630
}
2731

2832
/**
29-
* A call to a `window` event listener for the `MessageEvent`
30-
*/
31-
class PostMessageListeners extends DataFlow::CallNode {
32-
PostMessageListeners() {
33-
exists(WindowListeners listener |
34-
listener.getArgument(0).mayHaveStringValue("message") and
35-
this = listener
36-
)
37-
}
38-
}
39-
40-
/**
41-
* A function handler for the `MessageEvent`. It is the second argument of a `MessageEvent` listener
33+
* A function handler for the `MessageEvent`.
4234
*/
4335
class PostMessageHandler extends DataFlow::FunctionNode {
44-
PostMessageHandler() {
45-
exists(PostMessageListeners listener | this = listener.getArgument(1).getAFunctionValue())
46-
}
36+
PostMessageHandler() { exists(PostMessageEventHandler handler | this.getFunction() = handler) }
4737
}
4838

4939
/**
50-
* The `MessageEvent` received by the handler
40+
* The `MessageEvent` parameter received by the handler
5141
*/
5242
class PostMessageEvent extends DataFlow::SourceNode {
5343
PostMessageEvent() { exists(PostMessageHandler handler | this = handler.getParameter(0)) }
5444

45+
VarAccess event;
46+
EqualityTest astNode;
47+
48+
/**
49+
* Holds if an access on `MessageEvent.origin` is in an `EqualityTest` and there is no call of an insufficient verification method on `MessageEvent.origin`
50+
*/
51+
predicate hasOriginChecked() {
52+
exists(string prop | prop = "origin" or prop = "source" |
53+
astNode.getAnOperand().(PropAccess).accesses(event, prop) and
54+
event.mayReferToParameter*(this.asExpr()) and
55+
not this.hasOriginInsufficientlyChecked()
56+
)
57+
}
58+
5559
/**
56-
* Holds if a call to a method on `MessageEvent.origin` or a read of `MessageEvent.origin` is in an `if` statement
60+
* Holds if there is an insufficient method call (i.e indexOf) used to verify `MessageEvent.origin`
5761
*/
58-
predicate isOriginChecked() {
59-
exists(IfStmt ifStmt |
60-
ifStmt = this.getAPropertyRead("origin").getAMethodCall*().asExpr().getEnclosingStmt() or
61-
ifStmt = this.getAPropertyRead("origin").asExpr().getEnclosingStmt()
62+
predicate hasOriginInsufficientlyChecked() {
63+
exists(InsufficientOriginChecks insufficientChecks |
64+
this.getAPropertyRead("origin").getAMethodCall*() = insufficientChecks
6265
)
6366
}
6467
}
6568

66-
from PostMessageEvent event, PostMessageHandler handler
67-
where
68-
event = handler.getParameter(0) and
69-
not event.isOriginChecked()
70-
select "The `MessageEvent.origin` property is not checked.", event, handler
69+
from PostMessageEvent event
70+
where not event.hasOriginChecked()
71+
select event, "Missing or unsafe origin verification"

0 commit comments

Comments
 (0)