Skip to content

Commit 6d1634e

Browse files
authored
Merge pull request #4329 from erik-krogh/DVSA
Approved by esbena
2 parents 35985a9 + a0cbeb6 commit 6d1634e

File tree

16 files changed

+211
-0
lines changed

16 files changed

+211
-0
lines changed

change-notes/1.26/analysis-javascript.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
## General improvements
44

55
* Support for the following frameworks and libraries has been improved:
6+
- [AWS Serverless](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
7+
- [Alibaba Serverless](https://www.alibabacloud.com/help/doc-detail/156876.htm)
68
- [bluebird](https://www.npmjs.com/package/bluebird)
79
- [express](https://www.npmjs.com/package/express)
810
- [fast-json-stable-stringify](https://www.npmjs.com/package/fast-json-stable-stringify)

javascript/ql/src/javascript.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ import semmle.javascript.frameworks.PropertyProjection
9494
import semmle.javascript.frameworks.React
9595
import semmle.javascript.frameworks.ReactNative
9696
import semmle.javascript.frameworks.Request
97+
import semmle.javascript.frameworks.ServerLess
9798
import semmle.javascript.frameworks.ShellJS
9899
import semmle.javascript.frameworks.SystemCommandExecutors
99100
import semmle.javascript.frameworks.SQL
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* Provides classes and predicates for working with serverless handlers.
3+
* E.g. AWS: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html
4+
*/
5+
6+
import javascript
7+
8+
/**
9+
* Provides classes and predicates for working with serverless handlers.
10+
* In particular a `RemoteFlowSource` is added for AWS and Alibaba serverless.
11+
*/
12+
private module ServerLess {
13+
/**
14+
* Holds if the `.yml` file `ymlFile` contains a serverless configuration with `handler` and `codeURI` properties.
15+
* `codeURI` defaults to the empty string if no explicit value is set in the configuration.
16+
*/
17+
private predicate hasServerlessHandler(File ymlFile, string handler, string codeURI) {
18+
exists(YAMLMapping resource | ymlFile = resource.getFile() |
19+
// There exists at least "AWS::Serverless::Function" and "Aliyun::Serverless::Function"
20+
resource.lookup("Type").(YAMLScalar).getValue().regexpMatch(".*::Serverless::Function") and
21+
exists(YAMLMapping properties | properties = resource.lookup("Properties") |
22+
handler = properties.lookup("Handler").(YAMLScalar).getValue() and
23+
if exists(properties.lookup("CodeUri"))
24+
then codeURI = properties.lookup("CodeUri").(YAMLScalar).getValue()
25+
else codeURI = ""
26+
)
27+
)
28+
}
29+
30+
/**
31+
* Gets a string where an ending "/." is simplified to "/" (if it exists).
32+
*/
33+
bindingset[base]
34+
private string removeTrailingDot(string base) {
35+
if base.regexpMatch(".*/\\.")
36+
then result = base.substring(0, base.length() - 1)
37+
else result = base
38+
}
39+
40+
/**
41+
* Gets a string where a leading "./" is simplified to "" (if it exists).
42+
*/
43+
bindingset[base]
44+
private string removeLeadingDotSlash(string base) {
45+
if base.regexpMatch("\\./.*") then result = base.substring(2, base.length()) else result = base
46+
}
47+
48+
/**
49+
* Gets a path to a file from a `codeURI` property and a file name from a serverless configuration.
50+
*
51+
* For example if `codeURI` is "function/." and `file` is "index", then the result becomes "function/index.js".
52+
*/
53+
bindingset[codeURI, file]
54+
private string getPathFromHandlerProperties(string codeURI, string file) {
55+
exists(string folder | folder = removeLeadingDotSlash(removeTrailingDot(codeURI)) |
56+
result = folder + file + ".js"
57+
)
58+
}
59+
60+
/**
61+
* Holds if `file` has a serverless handler function with name `func`.
62+
*/
63+
private predicate hasServerlessHandler(File file, string func) {
64+
exists(File ymlFile, string handler, string codeURI, string fileName |
65+
hasServerlessHandler(ymlFile, handler, codeURI) and
66+
// Splits a `handler` into two components. The `fileName` to the left of the dot, and the `func` to the right.
67+
// E.g. if `handler` is "index.foo", then `fileName` is "index" and `func` is "foo".
68+
exists(string pattern | pattern = "(.*)\\.(.*)" |
69+
fileName = handler.regexpCapture(pattern, 1) and
70+
func = handler.regexpCapture(pattern, 2)
71+
)
72+
|
73+
file.getAbsolutePath() =
74+
ymlFile.getParentContainer().getAbsolutePath() + "/" +
75+
getPathFromHandlerProperties(codeURI, fileName)
76+
)
77+
}
78+
79+
/**
80+
* Gets a function that is a serverless request handler.
81+
*
82+
* For example: if an AWS serverless resource contains the following properties (in the "template.yml" file):
83+
* ```yaml
84+
* Handler: mylibrary.handler
85+
* Runtime: nodejs12.x
86+
* CodeUri: backend/src/
87+
* ```
88+
*
89+
* And a file "mylibrary.js" exists in the folder "backend/src" (relative to the "template.yml" file).
90+
* Then the result of this predicate is a function exported as "handler" from "mylibrary.js".
91+
* The "mylibrary.js" file could for example look like:
92+
*
93+
* ```JavaScript
94+
* module.exports.handler = function (event) { ... }
95+
* ```
96+
*/
97+
private DataFlow::FunctionNode getAServerlessHandler() {
98+
exists(File file, string handler, Module mod | hasServerlessHandler(file, handler) |
99+
mod.getFile() = file and
100+
result = mod.getAnExportedValue(handler).getAFunctionValue()
101+
)
102+
}
103+
104+
/**
105+
* A serverless request handler event, seen as a RemoteFlowSource.
106+
*/
107+
private class ServerlessHandlerEventAsRemoteFlow extends RemoteFlowSource {
108+
ServerlessHandlerEventAsRemoteFlow() { this = getAServerlessHandler().getParameter(0) }
109+
110+
override string getSourceType() { result = "Serverless event" }
111+
}
112+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ module CodeInjection {
8686
|
8787
this = c.getArgument(index)
8888
)
89+
or
90+
// node-serialize is not intended to be safe for untrusted inputs
91+
this = DataFlow::moduleMember("node-serialize", "unserialize").getACall().getArgument(0)
8992
}
9093
}
9194

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| tst1/backend/src/mylibrary.js:1:36:1:40 | event |
2+
| tst2/nodejs/index.js:1:36:1:40 | event |
3+
| tst3/function/index.js:1:36:1:40 | event |
4+
| tst4/app.js:1:36:1:40 | event |
5+
| tst5/app.js:1:36:1:40 | event |
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import javascript
2+
3+
query RemoteFlowSource remoteFlow() { any() }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports.handler = function (event) {
2+
console.log(event);
3+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
AWSTemplateFormatVersion: '2010-09-09'
2+
Transform: 'AWS::Serverless-2016-10-31'
3+
Description: 'Serverless thing'
4+
5+
Globals:
6+
Api:
7+
Cors:
8+
AllowMethods: "'*'"
9+
AllowHeaders: "'*'"
10+
AllowOrigin: "'*'"
11+
12+
Resources:
13+
OrderManagerJsFunction:
14+
Type: 'AWS::Serverless::Function'
15+
Properties:
16+
FunctionName: MY-SERVERLESS-THING
17+
Handler: mylibrary.handler
18+
Runtime: nodejs12.x
19+
CodeUri: backend/src/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports.handler = function (event) {
2+
console.log(event);
3+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Transform: 'Aliyun::Serverless-2018-04-03'
2+
Resources:
3+
fc-mongo:
4+
Type: 'Aliyun::Serverless::Service'
5+
Properties:
6+
Description: MyServiceThing
7+
nodejs:
8+
Type: 'Aliyun::Serverless::Function'
9+
Properties:
10+
Handler: index.handler
11+
Runtime: nodejs10
12+
CodeUri: nodejs/
13+
python:
14+
Type: 'Aliyun::Serverless::Function'
15+
Properties:
16+
Handler: 'index.handler'
17+
Runtime: python3
18+
CodeUri: python/

0 commit comments

Comments
 (0)