Skip to content

Commit 07ad596

Browse files
committed
Add coverage for express
1 parent c0e6d7c commit 07ad596

File tree

5 files changed

+87
-0
lines changed

5 files changed

+87
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* Provides classes for working with Cors connectors.
3+
*/
4+
5+
import javascript
6+
7+
/** Provides classes modeling [cors package](https://npmjs.com/package/cors) */
8+
module Cors {
9+
class Cors extends DataFlow::CallNode {
10+
/** Get an instanceof of `cors` */
11+
Cors() { this = DataFlow::moduleImport("cors").getAnInvocation() }
12+
13+
/** Get Cors configuration */
14+
DataFlow::Node getCorsArgument() { result = this.getArgument(0) }
15+
16+
/** Holds if cors is using default configuration */
17+
predicate isDefault() { this.getNumArgument() = 0 }
18+
19+
/** The value of origin */
20+
DataFlow::Node getOrigin() {
21+
result = this.getCorsArgument().getALocalSource().getAPropertyWrite("origin").getRhs()
22+
}
23+
}
24+
}

javascript/ql/lib/semmle/javascript/frameworks/Express.qll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import javascript
66
import semmle.javascript.frameworks.HTTP
77
import semmle.javascript.frameworks.ExpressModules
8+
import semmle.javascript.frameworks.Cors
89
private import semmle.javascript.dataflow.InferredTypes
910
private import semmle.javascript.frameworks.ConnectExpressShared::ConnectExpressShared
1011

@@ -1071,4 +1072,23 @@ module Express {
10711072

10721073
override predicate definitelyResumesDispatch() { none() }
10731074
}
1075+
1076+
class CorsConfiguration extends DataFlow::MethodCallNode {
1077+
/** Get an `app.use` with a cors object as argument */
1078+
CorsConfiguration() {
1079+
this = appCreation().getAMethodCall("use") and this.getArgument(0) instanceof Cors::Cors
1080+
}
1081+
1082+
/** Get Cors */
1083+
private Cors::Cors cors() { result = this.getArgument(0).(Cors::Cors) }
1084+
1085+
/** Get Cors configuration */
1086+
DataFlow::Node getCorsArgument() { result = cors().getCorsArgument() }
1087+
1088+
/** Holds if cors is using default configuration */
1089+
predicate isDefault() { cors().isDefault() }
1090+
1091+
/** Get Cors origin value */
1092+
DataFlow::Node getOrigin() { result = cors().getOrigin() }
1093+
}
10741094
}

javascript/ql/lib/semmle/javascript/security/dataflow/CorsPermissiveConfigurationCustomizations.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,11 @@ module CorsPermissiveConfiguration {
4444
)
4545
}
4646
}
47+
48+
/**
49+
* The value of cors origin when initializing the application.
50+
*/
51+
class ExpressCors extends Sink, DataFlow::ValueNode {
52+
ExpressCors() { exists(Express::CorsConfiguration config | this = config.getOrigin()) }
53+
}
4754
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const cors = require('cors');
2+
var express = require('express');
3+
4+
var https = require('https'),
5+
url = require('url');
6+
7+
var server = https.createServer(function () { });
8+
9+
server.on('request', function (req, res) {
10+
let user_origin = url.parse(req.url, true).query.origin;
11+
12+
// BAD: CORS too permissive, default value is *
13+
var app1 = express();
14+
app1.use(cors());
15+
16+
// GOOD: restrictive CORS
17+
var app2 = express();
18+
var corsOptions2 = {
19+
origin: ["https://example1.com", "https://example2.com"],
20+
};
21+
app2.use(cors(corsOptions2));
22+
23+
// BAD: CORS too permissive
24+
var app3 = express();
25+
var corsOption3 = {
26+
origin: '*'
27+
};
28+
app3.use(cors(corsOption3));
29+
30+
// BAD: CORS is controlled by user
31+
var app4 = express();
32+
var corsOption4 = {
33+
origin: user_origin
34+
};
35+
app4.use(cors(corsOption4));
36+
});

0 commit comments

Comments
 (0)