seaworthycode 1.1.1 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +269 -59
- package/dist/index.js.map +1 -1
- package/package.json +16 -12
- package/rules/external/configuration/insecure-cookie-flags.test.yaml +114 -0
- package/rules/external/configuration/insecure-cookie-flags.yaml +77 -0
- package/rules/external/configuration/missing-ssl-verification.test.yaml +130 -0
- package/rules/external/configuration/missing-ssl-verification.yaml +123 -0
- package/rules/external/data-exposure/debug-artifacts.test.yaml +143 -0
- package/rules/external/data-exposure/debug-artifacts.yaml +57 -0
- package/rules/external/data-exposure/hardcoded-ip.test.yaml +131 -0
- package/rules/external/data-exposure/hardcoded-ip.yaml +67 -0
- package/rules/external/data-exposure/localstorage-sensitive-data.test.yaml +58 -0
- package/rules/external/data-exposure/localstorage-sensitive-data.yaml +60 -0
- package/rules/external/dependencies/deprecated-functions.test.yaml +92 -0
- package/rules/external/dependencies/deprecated-functions.yaml +66 -0
- package/rules/external/ops/hardcoded-port.test.yaml +141 -0
- package/rules/external/ops/hardcoded-port.yaml +91 -0
- package/rules/external/ops/insecure-file-permissions.test.yaml +111 -0
- package/rules/external/ops/insecure-file-permissions.yaml +91 -0
- package/rules/external/resilience/missing-memory-limit.test.yaml +54 -0
- package/rules/external/resilience/missing-memory-limit.yaml +59 -0
- package/rules/external/resilience/missing-timeout-config.test.yaml +179 -0
- package/rules/external/resilience/missing-timeout-config.yaml +124 -0
- package/rules/external/security/broken-crypto-algorithm.test.yaml +104 -0
- package/rules/external/security/broken-crypto-algorithm.yaml +79 -0
- package/rules/external/security/http-method-override.test.yaml +40 -0
- package/rules/external/security/http-method-override.yaml +35 -0
- package/rules/external/security/http-no-tls.test.yaml +115 -0
- package/rules/external/security/http-no-tls.yaml +59 -0
- package/rules/external/security/path-traversal.test.yaml +188 -0
- package/rules/external/security/path-traversal.yaml +210 -0
- package/rules/external/security/unsafe-innerhtml.test.yaml +72 -0
- package/rules/external/security/unsafe-innerhtml.yaml +46 -0
- package/rules/external/security/untrusted-deserialization.test.yaml +79 -0
- package/rules/external/security/untrusted-deserialization.yaml +48 -0
- package/rules/external/security/weak-encryption-mode.test.yaml +126 -0
- package/rules/external/security/weak-encryption-mode.yaml +104 -0
- package/rules/external/security/weak-hash-algorithm.test.yaml +121 -0
- package/rules/external/security/weak-hash-algorithm.yaml +87 -0
- package/rules/external/security/xxe-parsing.test.yaml +76 -0
- package/rules/external/security/xxe-parsing.yaml +63 -0
- package/rules/internal/security/dangerous-eval.test.yaml +126 -0
- package/rules/internal/security/dangerous-eval.yaml +134 -0
- package/rules/internal/security/no-document-write.test.yaml +33 -0
- package/rules/internal/security/no-document-write.yaml +40 -0
- package/rules/internal/taint/MATRIX.md +16 -0
- package/rules/internal/taint/bash.test.yaml +84 -0
- package/rules/internal/taint/bash.yaml +166 -0
- package/rules/internal/taint/dvwa.test.yaml +217 -0
- package/rules/internal/taint/go.test.yaml +207 -0
- package/rules/internal/taint/go.yaml +325 -0
- package/rules/internal/taint/java.test.yaml +158 -0
- package/rules/internal/taint/java.yaml +318 -0
- package/rules/internal/taint/javascript.test.yaml +374 -0
- package/rules/internal/taint/javascript.yaml +439 -0
- package/rules/internal/taint/php.test.yaml +134 -0
- package/rules/internal/taint/php.yaml +331 -0
- package/rules/internal/taint/python.test.yaml +427 -0
- package/rules/internal/taint/python.yaml +636 -0
- package/rules/internal/taint/ruby.test.yaml +148 -0
- package/rules/internal/taint/ruby.yaml +233 -0
- package/rules/internal/taint/rust.test.yaml +585 -0
- package/rules/internal/taint/rust.yaml +483 -0
- package/rules/internal/taint/tsx.test.yaml +140 -0
- package/rules/internal/taint/tsx.yaml +51 -0
- package/rules/internal/taint/typescript.test.yaml +393 -0
- package/rules/internal/taint/typescript.yaml +660 -0
- package/wasm/tree-sitter-sql.wasm +0 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
language: typescript
|
|
2
|
+
cases:
|
|
3
|
+
- name: "AC-4.6: direct XSS flow from req.body to res.send in TS"
|
|
4
|
+
language: typescript
|
|
5
|
+
code: |
|
|
6
|
+
const x = req.body;
|
|
7
|
+
res.send(x);
|
|
8
|
+
expect:
|
|
9
|
+
count: 1
|
|
10
|
+
flows:
|
|
11
|
+
- sourceId: req.body
|
|
12
|
+
sinkId: res.send
|
|
13
|
+
|
|
14
|
+
- name: "AC-4.7: XSS sanitised by encodeURIComponent in TS — no finding"
|
|
15
|
+
language: typescript
|
|
16
|
+
code: |
|
|
17
|
+
res.send(encodeURIComponent(req.body));
|
|
18
|
+
expect:
|
|
19
|
+
count: 0
|
|
20
|
+
|
|
21
|
+
- name: "SQL injection in TS — req.query to db.query"
|
|
22
|
+
language: typescript
|
|
23
|
+
code: |
|
|
24
|
+
const q = req.query.id;
|
|
25
|
+
db.query("SELECT * FROM users WHERE id = " + q);
|
|
26
|
+
expect:
|
|
27
|
+
count: 1
|
|
28
|
+
flows:
|
|
29
|
+
- sourceId: req.query
|
|
30
|
+
sinkId: db.query
|
|
31
|
+
|
|
32
|
+
- name: "SQL injection sanitised by parameterised query in TS"
|
|
33
|
+
language: typescript
|
|
34
|
+
code: |
|
|
35
|
+
db.query("SELECT * FROM users WHERE id = ?", [req.query.id]);
|
|
36
|
+
expect:
|
|
37
|
+
count: 0
|
|
38
|
+
|
|
39
|
+
- name: "Sequelize query with req.query criteria"
|
|
40
|
+
language: typescript
|
|
41
|
+
code: |
|
|
42
|
+
const criteria = req.query.q;
|
|
43
|
+
models.sequelize.query(`SELECT * FROM Products WHERE name LIKE '%${criteria}%'`);
|
|
44
|
+
expect:
|
|
45
|
+
count: 2
|
|
46
|
+
flows:
|
|
47
|
+
- sourceId: req.query
|
|
48
|
+
sinkId: sequelize.query
|
|
49
|
+
- sourceId: req.query
|
|
50
|
+
sinkId: template-literal-sql
|
|
51
|
+
|
|
52
|
+
- name: "Safe parameterised Sequelize-style query"
|
|
53
|
+
language: typescript
|
|
54
|
+
code: |
|
|
55
|
+
models.sequelize.query("SELECT * FROM Products WHERE id = ?", [req.query.id]);
|
|
56
|
+
expect:
|
|
57
|
+
count: 0
|
|
58
|
+
|
|
59
|
+
- name: "URL injection in TS — req.query to res.redirect"
|
|
60
|
+
language: typescript
|
|
61
|
+
code: |
|
|
62
|
+
res.redirect(req.query.next);
|
|
63
|
+
expect:
|
|
64
|
+
count: 1
|
|
65
|
+
flows:
|
|
66
|
+
- sourceId: req.query
|
|
67
|
+
sinkId: res.redirect
|
|
68
|
+
|
|
69
|
+
- name: "Command injection in TS — process.argv to child_process.exec"
|
|
70
|
+
language: typescript
|
|
71
|
+
code: |
|
|
72
|
+
child_process.exec(process.argv[2]);
|
|
73
|
+
expect:
|
|
74
|
+
count: 1
|
|
75
|
+
flows:
|
|
76
|
+
- sourceId: process.argv
|
|
77
|
+
sinkId: child_process.exec
|
|
78
|
+
|
|
79
|
+
- name: "Path traversal in TS — req.params to fs.readFile"
|
|
80
|
+
language: typescript
|
|
81
|
+
code: |
|
|
82
|
+
fs.readFile(req.params.file);
|
|
83
|
+
expect:
|
|
84
|
+
count: 1
|
|
85
|
+
flows:
|
|
86
|
+
- sourceId: req.params
|
|
87
|
+
sinkId: fs.readFile-path
|
|
88
|
+
|
|
89
|
+
- name: "Path traversal sanitised in TS — path.resolve"
|
|
90
|
+
language: typescript
|
|
91
|
+
code: |
|
|
92
|
+
fs.readFile(path.resolve("/safe", req.params.file));
|
|
93
|
+
expect:
|
|
94
|
+
count: 0
|
|
95
|
+
|
|
96
|
+
- name: "Safe fs.writeFile with literal path — zero flows"
|
|
97
|
+
language: typescript
|
|
98
|
+
code: |
|
|
99
|
+
fs.writeFile('./data/app-config.json', 'static');
|
|
100
|
+
expect:
|
|
101
|
+
count: 0
|
|
102
|
+
|
|
103
|
+
- name: "Juice Shop-style codingChallenges read — zero flows"
|
|
104
|
+
language: typescript
|
|
105
|
+
code: |
|
|
106
|
+
import fs from 'fs';
|
|
107
|
+
fs.readFile('./data/codingchallenges/readme.md');
|
|
108
|
+
expect:
|
|
109
|
+
count: 0
|
|
110
|
+
|
|
111
|
+
- name: "Path traversal in TS — req.params to res.sendFile"
|
|
112
|
+
language: typescript
|
|
113
|
+
code: |
|
|
114
|
+
res.sendFile(req.params.file);
|
|
115
|
+
expect:
|
|
116
|
+
count: 1
|
|
117
|
+
flows:
|
|
118
|
+
- sourceId: req.params
|
|
119
|
+
sinkId: res.sendFile
|
|
120
|
+
|
|
121
|
+
- name: "Path traversal in TS — req.query to res.download"
|
|
122
|
+
language: typescript
|
|
123
|
+
code: |
|
|
124
|
+
res.download(req.query.path);
|
|
125
|
+
expect:
|
|
126
|
+
count: 1
|
|
127
|
+
flows:
|
|
128
|
+
- sourceId: req.query
|
|
129
|
+
sinkId: res.download
|
|
130
|
+
|
|
131
|
+
- name: "URL injection in TS — process.env to location.href"
|
|
132
|
+
language: typescript
|
|
133
|
+
code: |
|
|
134
|
+
window.location.href = process.env.REDIRECT_URL;
|
|
135
|
+
expect:
|
|
136
|
+
count: 1
|
|
137
|
+
flows:
|
|
138
|
+
- sourceId: process.env
|
|
139
|
+
sinkId: location.href
|
|
140
|
+
|
|
141
|
+
- name: "URL injection sanitised by encodeURIComponent in TS"
|
|
142
|
+
language: typescript
|
|
143
|
+
code: |
|
|
144
|
+
res.redirect(encodeURIComponent(req.query.redirect));
|
|
145
|
+
expect:
|
|
146
|
+
count: 0
|
|
147
|
+
|
|
148
|
+
- name: "TS — Function call stops propagation"
|
|
149
|
+
language: typescript
|
|
150
|
+
code: |
|
|
151
|
+
const x = req.body;
|
|
152
|
+
helper(x);
|
|
153
|
+
eval(x);
|
|
154
|
+
expect:
|
|
155
|
+
count: 1
|
|
156
|
+
flows:
|
|
157
|
+
- sourceId: req.body
|
|
158
|
+
sinkId: eval
|
|
159
|
+
|
|
160
|
+
- name: "TS — Prototype pollution with merge"
|
|
161
|
+
language: typescript
|
|
162
|
+
code: |
|
|
163
|
+
const target = {};
|
|
164
|
+
merge(target, req.body);
|
|
165
|
+
expect:
|
|
166
|
+
count: 1
|
|
167
|
+
flows:
|
|
168
|
+
- sourceId: req.body
|
|
169
|
+
sinkId: merge-deep
|
|
170
|
+
|
|
171
|
+
- name: "TS — Object.freeze sanitises prototype pollution"
|
|
172
|
+
language: typescript
|
|
173
|
+
code: |
|
|
174
|
+
const target = {};
|
|
175
|
+
Object.assign(target, Object.freeze(req.body));
|
|
176
|
+
expect:
|
|
177
|
+
count: 0
|
|
178
|
+
|
|
179
|
+
- name: "TS — API XSS from req.body to res.json"
|
|
180
|
+
language: typescript
|
|
181
|
+
code: |
|
|
182
|
+
res.json(req.body.label);
|
|
183
|
+
expect:
|
|
184
|
+
count: 1
|
|
185
|
+
flows:
|
|
186
|
+
- sourceId: req.body
|
|
187
|
+
sinkId: res.json
|
|
188
|
+
|
|
189
|
+
- name: "TS — API XSS safe — res.json with literal object"
|
|
190
|
+
language: typescript
|
|
191
|
+
code: |
|
|
192
|
+
res.json({ ok: true });
|
|
193
|
+
expect:
|
|
194
|
+
count: 0
|
|
195
|
+
|
|
196
|
+
- name: "TS — destructuring SQLi from req.query"
|
|
197
|
+
language: typescript
|
|
198
|
+
code: |
|
|
199
|
+
const { id } = req.query;
|
|
200
|
+
db.query("SELECT * FROM users WHERE id = " + id);
|
|
201
|
+
expect:
|
|
202
|
+
count: 1
|
|
203
|
+
flows:
|
|
204
|
+
- sourceId: req.query
|
|
205
|
+
sinkId: db.query
|
|
206
|
+
|
|
207
|
+
- name: "TS — MongoDB $where injection"
|
|
208
|
+
language: typescript
|
|
209
|
+
code: |
|
|
210
|
+
Product.find({ $where: req.query.q });
|
|
211
|
+
expect:
|
|
212
|
+
count: 1
|
|
213
|
+
flows:
|
|
214
|
+
- sourceId: req.query
|
|
215
|
+
sinkId: Model.find-$where
|
|
216
|
+
|
|
217
|
+
- name: "TS — upload path traversal via fs.writeFile"
|
|
218
|
+
language: typescript
|
|
219
|
+
code: |
|
|
220
|
+
fs.writeFile(req.body.path, req.body.data);
|
|
221
|
+
expect:
|
|
222
|
+
count: 1
|
|
223
|
+
flows:
|
|
224
|
+
- sourceId: req.body
|
|
225
|
+
sinkId: fs.writeFile-path
|
|
226
|
+
|
|
227
|
+
- name: "TS — DOMPurify sanitises res.json XSS"
|
|
228
|
+
language: typescript
|
|
229
|
+
code: |
|
|
230
|
+
res.json(DOMPurify.sanitize(req.body.x));
|
|
231
|
+
expect:
|
|
232
|
+
count: 0
|
|
233
|
+
|
|
234
|
+
- name: "TS — optional chaining req?.body to res.send"
|
|
235
|
+
language: typescript
|
|
236
|
+
code: |
|
|
237
|
+
const x = req?.body;
|
|
238
|
+
res.send(x);
|
|
239
|
+
expect:
|
|
240
|
+
count: 1
|
|
241
|
+
flows:
|
|
242
|
+
- sourceId: req.body
|
|
243
|
+
sinkId: res.send
|
|
244
|
+
|
|
245
|
+
- name: "TS — multer req.file.path to fs.writeFile"
|
|
246
|
+
language: typescript
|
|
247
|
+
code: |
|
|
248
|
+
fs.writeFile(req.file.path, buf);
|
|
249
|
+
expect:
|
|
250
|
+
count: 1
|
|
251
|
+
flows:
|
|
252
|
+
- sourceId: req.file.path
|
|
253
|
+
sinkId: fs.writeFile-path
|
|
254
|
+
|
|
255
|
+
- name: "TS — Fastify request.body to res.send XSS"
|
|
256
|
+
language: typescript
|
|
257
|
+
code: |
|
|
258
|
+
const x = request.body;
|
|
259
|
+
res.send(x);
|
|
260
|
+
expect:
|
|
261
|
+
count: 1
|
|
262
|
+
flows:
|
|
263
|
+
- sourceId: fastify.request.body
|
|
264
|
+
sinkId: res.send
|
|
265
|
+
|
|
266
|
+
- name: "TS — req.headers to res.redirect"
|
|
267
|
+
language: typescript
|
|
268
|
+
code: |
|
|
269
|
+
res.redirect(req.headers.referer);
|
|
270
|
+
expect:
|
|
271
|
+
count: 1
|
|
272
|
+
flows:
|
|
273
|
+
- sourceId: req.headers
|
|
274
|
+
sinkId: res.redirect
|
|
275
|
+
|
|
276
|
+
- name: "TS — Prisma $queryRaw SQLi"
|
|
277
|
+
language: typescript
|
|
278
|
+
code: |
|
|
279
|
+
const id = req.query.id;
|
|
280
|
+
prisma.$queryRaw("SELECT * FROM users WHERE id = " + id);
|
|
281
|
+
expect:
|
|
282
|
+
count: 1
|
|
283
|
+
flows:
|
|
284
|
+
- sourceId: req.query
|
|
285
|
+
sinkId: prisma.queryRaw
|
|
286
|
+
|
|
287
|
+
- name: "TS — child_process.spawn command injection"
|
|
288
|
+
language: typescript
|
|
289
|
+
code: |
|
|
290
|
+
child_process.spawn(process.argv[2]);
|
|
291
|
+
expect:
|
|
292
|
+
count: 1
|
|
293
|
+
flows:
|
|
294
|
+
- sourceId: process.argv
|
|
295
|
+
sinkId: child_process.spawn
|
|
296
|
+
|
|
297
|
+
- name: "TS — child_process.spawn with constant argv — no flow"
|
|
298
|
+
language: typescript
|
|
299
|
+
code: |
|
|
300
|
+
child_process.spawn('ls', ['-la']);
|
|
301
|
+
expect:
|
|
302
|
+
count: 0
|
|
303
|
+
|
|
304
|
+
- name: "TS — NestJS @Body to res.send XSS"
|
|
305
|
+
language: typescript
|
|
306
|
+
code: |
|
|
307
|
+
function handler(@Body() body: unknown) {
|
|
308
|
+
res.send(body);
|
|
309
|
+
}
|
|
310
|
+
expect:
|
|
311
|
+
count: 1
|
|
312
|
+
flows:
|
|
313
|
+
- sourceId: nest.decorator-body
|
|
314
|
+
sinkId: res.send
|
|
315
|
+
|
|
316
|
+
- name: "TS — Hono c.req.body to res.send"
|
|
317
|
+
language: typescript
|
|
318
|
+
code: |
|
|
319
|
+
const x = c.req.body;
|
|
320
|
+
res.send(x);
|
|
321
|
+
expect:
|
|
322
|
+
count: 1
|
|
323
|
+
flows:
|
|
324
|
+
- sourceId: hono.req.body
|
|
325
|
+
sinkId: res.send
|
|
326
|
+
|
|
327
|
+
- name: "TS — GraphQL @Args to db.query SQLi"
|
|
328
|
+
language: typescript
|
|
329
|
+
code: |
|
|
330
|
+
function resolver(@Args('id') args: string) {
|
|
331
|
+
db.query("SELECT * FROM t WHERE id = " + args);
|
|
332
|
+
}
|
|
333
|
+
expect:
|
|
334
|
+
count: 1
|
|
335
|
+
flows:
|
|
336
|
+
- sourceId: graphql.args
|
|
337
|
+
sinkId: db.query
|
|
338
|
+
|
|
339
|
+
- name: "TS — Next.js redirect URL injection"
|
|
340
|
+
language: typescript
|
|
341
|
+
code: |
|
|
342
|
+
redirect(req.query.next);
|
|
343
|
+
expect:
|
|
344
|
+
count: 1
|
|
345
|
+
flows:
|
|
346
|
+
- sourceId: req.query
|
|
347
|
+
sinkId: next.redirect
|
|
348
|
+
|
|
349
|
+
- name: "TS — fs/promises readFile path traversal"
|
|
350
|
+
language: typescript
|
|
351
|
+
code: |
|
|
352
|
+
import * as fs from 'fs';
|
|
353
|
+
fs.promises.readFile(req.params.path);
|
|
354
|
+
expect:
|
|
355
|
+
count: 1
|
|
356
|
+
flows:
|
|
357
|
+
- sourceId: req.params
|
|
358
|
+
sinkId: fs.promises.readFile
|
|
359
|
+
|
|
360
|
+
- name: "TS — WebSocket on message to res.send XSS"
|
|
361
|
+
language: typescript
|
|
362
|
+
code: |
|
|
363
|
+
ws.on('message', (data: string) => {
|
|
364
|
+
res.send(data);
|
|
365
|
+
});
|
|
366
|
+
expect:
|
|
367
|
+
count: 1
|
|
368
|
+
flows:
|
|
369
|
+
- sourceId: websocket.message
|
|
370
|
+
sinkId: res.send
|
|
371
|
+
|
|
372
|
+
- name: "TS — code-execution sanitised static Function — no flow"
|
|
373
|
+
language: typescript
|
|
374
|
+
code: |
|
|
375
|
+
const x = req.body;
|
|
376
|
+
new Function("return 1");
|
|
377
|
+
expect:
|
|
378
|
+
count: 0
|
|
379
|
+
|
|
380
|
+
- name: "TS — url-injection sanitised encodeURIComponent on redirect"
|
|
381
|
+
language: typescript
|
|
382
|
+
code: |
|
|
383
|
+
res.redirect(encodeURIComponent(req.query.next));
|
|
384
|
+
expect:
|
|
385
|
+
count: 0
|
|
386
|
+
|
|
387
|
+
- name: "TS — zod.parse blocks XSS to res.send"
|
|
388
|
+
language: typescript
|
|
389
|
+
code: |
|
|
390
|
+
const parsed = z.object({ x: z.string() }).parse(req.body);
|
|
391
|
+
res.send(parsed.x);
|
|
392
|
+
expect:
|
|
393
|
+
count: 0
|