Skip to content

Commit ba44ebe

Browse files
committed
better support for browser based fetch API
1 parent 3622fb8 commit ba44ebe

3 files changed

Lines changed: 59 additions & 4 deletions

File tree

javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,22 +1145,31 @@ module NodeJSLib {
11451145
DataFlow::SourceNode moduleImport() {
11461146
result = DataFlow::moduleImport(["node-fetch", "cross-fetch", "isomorphic-fetch"])
11471147
or
1148-
result = DataFlow::globalVarRef("fetch")
1148+
result = DataFlow::globalVarRef("fetch") // https://fetch.spec.whatwg.org/#fetch-api
1149+
}
1150+
1151+
/**
1152+
* Gets an instance of the `Headers` class.
1153+
*/
1154+
private DataFlow::NewNode header() {
1155+
result = moduleImport().getAConstructorInvocation("Headers")
1156+
or
1157+
result = DataFlow::globalVarRef("Headers").getAnInstantiation() // https://fetch.spec.whatwg.org/#headers-class
11491158
}
11501159

11511160
/** An expression that is passed as `http.request({ auth: <expr> }, ...)`. */
1152-
class FetchAuthorization extends CredentialsExpr {
1161+
private class FetchAuthorization extends CredentialsExpr {
11531162
FetchAuthorization() {
11541163
exists(DataFlow::Node headers |
1155-
headers = moduleImport().getAConstructorInvocation("Headers").getArgument(0)
1164+
headers = header().getArgument(0)
11561165
or
11571166
headers = moduleImport().getACall().getOptionArgument(1, "headers")
11581167
|
11591168
this = headers.getALocalSource().getAPropertyWrite("Authorization").getRhs().asExpr()
11601169
)
11611170
or
11621171
exists(DataFlow::MethodCallNode appendCall |
1163-
appendCall = moduleImport().getAConstructorInvocation("Headers").getAMethodCall(["append", "set"]) and
1172+
appendCall = header().getAMethodCall(["append", "set"]) and
11641173
appendCall.getArgument(0).mayHaveStringValue("Authorization") and
11651174
this = appendCall.getArgument(1).asExpr()
11661175
)

javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,20 @@ nodes
185185
| HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` |
186186
| HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` |
187187
| HardcodedCredentials.js:204:44:204:47 | AUTH |
188+
| HardcodedCredentials.js:214:11:214:25 | USER |
189+
| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' |
190+
| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' |
191+
| HardcodedCredentials.js:215:11:215:25 | PASS |
192+
| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' |
193+
| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' |
194+
| HardcodedCredentials.js:216:11:216:49 | AUTH |
195+
| HardcodedCredentials.js:216:18:216:49 | base64. ... PASS}`) |
196+
| HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` |
197+
| HardcodedCredentials.js:216:35:216:38 | USER |
198+
| HardcodedCredentials.js:216:43:216:46 | PASS |
199+
| HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` |
200+
| HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` |
201+
| HardcodedCredentials.js:221:46:221:49 | AUTH |
188202
edges
189203
| HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' |
190204
| HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' |
@@ -265,6 +279,19 @@ edges
265279
| HardcodedCredentials.js:195:46:195:49 | AUTH | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` |
266280
| HardcodedCredentials.js:204:44:204:47 | AUTH | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` |
267281
| HardcodedCredentials.js:204:44:204:47 | AUTH | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` |
282+
| HardcodedCredentials.js:214:11:214:25 | USER | HardcodedCredentials.js:216:35:216:38 | USER |
283+
| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:11:214:25 | USER |
284+
| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:11:214:25 | USER |
285+
| HardcodedCredentials.js:215:11:215:25 | PASS | HardcodedCredentials.js:216:43:216:46 | PASS |
286+
| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:11:215:25 | PASS |
287+
| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:11:215:25 | PASS |
288+
| HardcodedCredentials.js:216:11:216:49 | AUTH | HardcodedCredentials.js:221:46:221:49 | AUTH |
289+
| HardcodedCredentials.js:216:18:216:49 | base64. ... PASS}`) | HardcodedCredentials.js:216:11:216:49 | AUTH |
290+
| HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` | HardcodedCredentials.js:216:18:216:49 | base64. ... PASS}`) |
291+
| HardcodedCredentials.js:216:35:216:38 | USER | HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` |
292+
| HardcodedCredentials.js:216:43:216:46 | PASS | HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` |
293+
| HardcodedCredentials.js:221:46:221:49 | AUTH | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` |
294+
| HardcodedCredentials.js:221:46:221:49 | AUTH | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` |
268295
#select
269296
| HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | The hard-coded value "dbuser" is used as $@. | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | user name |
270297
| HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | password |
@@ -327,3 +354,5 @@ edges
327354
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | authorization headers |
328355
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | authorization headers |
329356
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization headers |
357+
| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization headers |
358+
| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization headers |

javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,21 @@
206206
method: 'get',
207207
headers: headers2
208208
});
209+
});
210+
211+
(function () {
212+
const base64 = require('base-64');
213+
214+
const USER = 'sdsdag';
215+
const PASS = 'sdsdag';
216+
const AUTH = base64.encode(`${USER}:${PASS}`);
217+
218+
// browser API
219+
var headers = new Headers();
220+
headers.append("Content-Type", 'application/json');
221+
headers.append("Authorization", `Basic ${AUTH}`);
222+
fetch(ENDPOINT, {
223+
method: 'get',
224+
headers: headers
225+
});
209226
});

0 commit comments

Comments
 (0)