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.
Files changed (68) hide show
  1. package/dist/index.js +269 -59
  2. package/dist/index.js.map +1 -1
  3. package/package.json +16 -12
  4. package/rules/external/configuration/insecure-cookie-flags.test.yaml +114 -0
  5. package/rules/external/configuration/insecure-cookie-flags.yaml +77 -0
  6. package/rules/external/configuration/missing-ssl-verification.test.yaml +130 -0
  7. package/rules/external/configuration/missing-ssl-verification.yaml +123 -0
  8. package/rules/external/data-exposure/debug-artifacts.test.yaml +143 -0
  9. package/rules/external/data-exposure/debug-artifacts.yaml +57 -0
  10. package/rules/external/data-exposure/hardcoded-ip.test.yaml +131 -0
  11. package/rules/external/data-exposure/hardcoded-ip.yaml +67 -0
  12. package/rules/external/data-exposure/localstorage-sensitive-data.test.yaml +58 -0
  13. package/rules/external/data-exposure/localstorage-sensitive-data.yaml +60 -0
  14. package/rules/external/dependencies/deprecated-functions.test.yaml +92 -0
  15. package/rules/external/dependencies/deprecated-functions.yaml +66 -0
  16. package/rules/external/ops/hardcoded-port.test.yaml +141 -0
  17. package/rules/external/ops/hardcoded-port.yaml +91 -0
  18. package/rules/external/ops/insecure-file-permissions.test.yaml +111 -0
  19. package/rules/external/ops/insecure-file-permissions.yaml +91 -0
  20. package/rules/external/resilience/missing-memory-limit.test.yaml +54 -0
  21. package/rules/external/resilience/missing-memory-limit.yaml +59 -0
  22. package/rules/external/resilience/missing-timeout-config.test.yaml +179 -0
  23. package/rules/external/resilience/missing-timeout-config.yaml +124 -0
  24. package/rules/external/security/broken-crypto-algorithm.test.yaml +104 -0
  25. package/rules/external/security/broken-crypto-algorithm.yaml +79 -0
  26. package/rules/external/security/http-method-override.test.yaml +40 -0
  27. package/rules/external/security/http-method-override.yaml +35 -0
  28. package/rules/external/security/http-no-tls.test.yaml +115 -0
  29. package/rules/external/security/http-no-tls.yaml +59 -0
  30. package/rules/external/security/path-traversal.test.yaml +188 -0
  31. package/rules/external/security/path-traversal.yaml +210 -0
  32. package/rules/external/security/unsafe-innerhtml.test.yaml +72 -0
  33. package/rules/external/security/unsafe-innerhtml.yaml +46 -0
  34. package/rules/external/security/untrusted-deserialization.test.yaml +79 -0
  35. package/rules/external/security/untrusted-deserialization.yaml +48 -0
  36. package/rules/external/security/weak-encryption-mode.test.yaml +126 -0
  37. package/rules/external/security/weak-encryption-mode.yaml +104 -0
  38. package/rules/external/security/weak-hash-algorithm.test.yaml +121 -0
  39. package/rules/external/security/weak-hash-algorithm.yaml +87 -0
  40. package/rules/external/security/xxe-parsing.test.yaml +76 -0
  41. package/rules/external/security/xxe-parsing.yaml +63 -0
  42. package/rules/internal/security/dangerous-eval.test.yaml +126 -0
  43. package/rules/internal/security/dangerous-eval.yaml +134 -0
  44. package/rules/internal/security/no-document-write.test.yaml +33 -0
  45. package/rules/internal/security/no-document-write.yaml +40 -0
  46. package/rules/internal/taint/MATRIX.md +16 -0
  47. package/rules/internal/taint/bash.test.yaml +84 -0
  48. package/rules/internal/taint/bash.yaml +166 -0
  49. package/rules/internal/taint/dvwa.test.yaml +217 -0
  50. package/rules/internal/taint/go.test.yaml +207 -0
  51. package/rules/internal/taint/go.yaml +325 -0
  52. package/rules/internal/taint/java.test.yaml +158 -0
  53. package/rules/internal/taint/java.yaml +318 -0
  54. package/rules/internal/taint/javascript.test.yaml +374 -0
  55. package/rules/internal/taint/javascript.yaml +439 -0
  56. package/rules/internal/taint/php.test.yaml +134 -0
  57. package/rules/internal/taint/php.yaml +331 -0
  58. package/rules/internal/taint/python.test.yaml +427 -0
  59. package/rules/internal/taint/python.yaml +636 -0
  60. package/rules/internal/taint/ruby.test.yaml +148 -0
  61. package/rules/internal/taint/ruby.yaml +233 -0
  62. package/rules/internal/taint/rust.test.yaml +585 -0
  63. package/rules/internal/taint/rust.yaml +483 -0
  64. package/rules/internal/taint/tsx.test.yaml +140 -0
  65. package/rules/internal/taint/tsx.yaml +51 -0
  66. package/rules/internal/taint/typescript.test.yaml +393 -0
  67. package/rules/internal/taint/typescript.yaml +660 -0
  68. package/wasm/tree-sitter-sql.wasm +0 -0
@@ -0,0 +1,104 @@
1
+ rule-id: security.broken-crypto-algorithm
2
+
3
+ cases:
4
+ - name: triggers on crypto.createCipher in javascript
5
+ language: javascript
6
+ code: |
7
+ const crypto = require('crypto')
8
+ const cipher = crypto.createCipher('aes192', key)
9
+ expect:
10
+ count: 1
11
+ severity: medium
12
+
13
+ - name: triggers on crypto.createCipher in typescript
14
+ language: typescript
15
+ code: |
16
+ import crypto from 'crypto'
17
+ const cipher = crypto.createCipher('aes192', key)
18
+ expect:
19
+ count: 1
20
+ severity: medium
21
+
22
+ - name: triggers on crypto.createCipher in tsx
23
+ language: tsx
24
+ code: |
25
+ import crypto from 'crypto'
26
+ const cipher = crypto.createCipher('aes', key)
27
+ expect:
28
+ count: 1
29
+ severity: medium
30
+
31
+ - name: triggers on DES.new in python
32
+ language: python
33
+ code: |
34
+ from Crypto.Cipher import DES
35
+ cipher = DES.new(key, DES.MODE_ECB)
36
+ expect:
37
+ count: 1
38
+ severity: medium
39
+
40
+ - name: triggers on base64 in bash
41
+ language: bash
42
+ code: |
43
+ base64 secret.txt > secret.enc
44
+ expect:
45
+ count: 1
46
+ severity: medium
47
+
48
+ - name: ignores safe API
49
+ language: javascript
50
+ code: |
51
+ const crypto = require('crypto')
52
+ const hash = crypto.createHash('sha256')
53
+ expect:
54
+ count: 0
55
+
56
+ - name: ignores safe API in typescript
57
+ language: typescript
58
+ code: |
59
+ import crypto from 'crypto'
60
+ const hash = crypto.createHash('sha256')
61
+ expect:
62
+ count: 0
63
+
64
+ - name: ignores unrelated code
65
+ language: python
66
+ code: |
67
+ result = 1 + 2
68
+ expect:
69
+ count: 0
70
+
71
+ - name: ignores sha256sum in bash
72
+ language: bash
73
+ code: |
74
+ sha256sum secret.txt
75
+ expect:
76
+ count: 0
77
+
78
+ - name: triggers on des in rust
79
+ language: rust
80
+ code: |
81
+ cipher.des()
82
+ expect:
83
+ count: 1
84
+ severity: medium
85
+
86
+ - name: triggers on Cipher DES in java
87
+ language: java
88
+ code: |
89
+ class T {
90
+ void f() throws Exception {
91
+ javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("DES");
92
+ }
93
+ }
94
+ expect:
95
+ count: 1
96
+ severity: medium
97
+
98
+ - name: triggers on OpenSSL Cipher RC4 in ruby
99
+ language: ruby
100
+ code: |
101
+ OpenSSL::Cipher.new('RC4')
102
+ expect:
103
+ count: 1
104
+ severity: medium
@@ -0,0 +1,79 @@
1
+ # source: clean-room
2
+ # licence: MIT
3
+ # vendored-at: 2026-05-20
4
+ # verified-by: Seaworthy team
5
+ # attribution: CWE-327
6
+ id: security.broken-crypto-algorithm
7
+ severity: medium
8
+ category: security
9
+ min-tier: pro
10
+ languages: [javascript, typescript, tsx, python, bash, rust, java, ruby]
11
+
12
+ copy:
13
+ name-key: checks.broken-crypto-algorithm.name
14
+ description-key: checks.broken-crypto-algorithm.description
15
+ message-key: checks.broken-crypto-algorithm.message
16
+ degraded-key: checks.broken-crypto-algorithm.degraded
17
+ remediation-key: remediation.security.broken-crypto-algorithm
18
+
19
+ confidence: high
20
+
21
+ queries:
22
+ javascript: |
23
+ (call_expression
24
+ function: (member_expression
25
+ object: (identifier) @obj
26
+ property: (property_identifier) @method)
27
+ (#eq? @obj "crypto")
28
+ (#eq? @method "createCipher")) @match
29
+ typescript: |
30
+ (call_expression
31
+ function: (member_expression
32
+ object: (identifier) @obj
33
+ property: (property_identifier) @method)
34
+ (#eq? @obj "crypto")
35
+ (#eq? @method "createCipher")) @match
36
+ tsx: |
37
+ (call_expression
38
+ function: (member_expression
39
+ object: (identifier) @obj
40
+ property: (property_identifier) @method)
41
+ (#eq? @obj "crypto")
42
+ (#eq? @method "createCipher")) @match
43
+ python: |
44
+ (call
45
+ function: (attribute
46
+ object: (identifier) @obj
47
+ attribute: (identifier) @method)
48
+ (#eq? @obj "DES")
49
+ (#eq? @method "new")) @match
50
+ bash: |
51
+ (command
52
+ name: (command_name (word) @cmd)
53
+ (#match? @cmd "^(base64|rot13)$")) @match
54
+ rust: |
55
+ (call_expression
56
+ function: (field_expression
57
+ field: (field_identifier) @func
58
+ (#match? @func "^(des|rc4)$"))) @match
59
+ java: |
60
+ (method_invocation
61
+ name: (identifier) @method
62
+ (#eq? @method "getInstance")
63
+ arguments: (argument_list
64
+ (string_literal
65
+ (string_fragment) @algo)
66
+ (#match? @algo "^(DES|des|RC4|rc4|Blowfish|blowfish)$"))) @match
67
+
68
+ ruby: |
69
+ (call
70
+ receiver: (scope_resolution
71
+ scope: (constant) @scope (#eq? @scope "OpenSSL")
72
+ name: (constant) @name (#eq? @name "Cipher"))
73
+ method: (identifier) @method (#eq? @method "new")
74
+ arguments: (argument_list
75
+ (string
76
+ (string_content) @algo
77
+ (#match? @algo "^(DES|des|RC4|rc4|Blowfish|blowfish)$")))) @match
78
+
79
+ message-captures: [match]
@@ -0,0 +1,40 @@
1
+ rule-id: security.http-method-override
2
+
3
+ cases:
4
+ - name: triggers on methodOverride in javascript
5
+ language: javascript
6
+ code: |
7
+ app.use(methodOverride('_method'))
8
+ expect:
9
+ count: 1
10
+ severity: medium
11
+
12
+ - name: triggers on methodOverride in typescript
13
+ language: typescript
14
+ code: |
15
+ app.use(methodOverride())
16
+ expect:
17
+ count: 1
18
+ severity: medium
19
+
20
+ - name: triggers on methodOverride in tsx
21
+ language: tsx
22
+ code: |
23
+ app.use(methodOverride('X-HTTP-Method-Override'))
24
+ expect:
25
+ count: 1
26
+ severity: medium
27
+
28
+ - name: ignores unrelated middleware
29
+ language: javascript
30
+ code: |
31
+ app.use(helmet())
32
+ expect:
33
+ count: 0
34
+
35
+ - name: ignores unrelated middleware in typescript
36
+ language: typescript
37
+ code: |
38
+ app.use(helmet())
39
+ expect:
40
+ count: 0
@@ -0,0 +1,35 @@
1
+ # source: clean-room
2
+ # licence: MIT
3
+ # vendored-at: 2026-05-20
4
+ # verified-by: Seaworthy team
5
+ # attribution: CWE-444
6
+ id: security.http-method-override
7
+ severity: medium
8
+ category: security
9
+ min-tier: pro
10
+ languages: [javascript, typescript, tsx]
11
+
12
+ copy:
13
+ name-key: checks.http-method-override.name
14
+ description-key: checks.http-method-override.description
15
+ message-key: checks.http-method-override.message
16
+ degraded-key: checks.http-method-override.degraded
17
+ remediation-key: remediation.security.http-method-override
18
+
19
+ confidence: medium
20
+
21
+ queries:
22
+ javascript: |
23
+ (call_expression
24
+ function: (identifier) @func
25
+ (#eq? @func "methodOverride")) @match
26
+ typescript: |
27
+ (call_expression
28
+ function: (identifier) @func
29
+ (#eq? @func "methodOverride")) @match
30
+ tsx: |
31
+ (call_expression
32
+ function: (identifier) @func
33
+ (#eq? @func "methodOverride")) @match
34
+
35
+ message-captures: [match]
@@ -0,0 +1,115 @@
1
+ rule-id: security.http-no-tls
2
+
3
+ cases:
4
+ - name: triggers on http URL in javascript
5
+ language: javascript
6
+ code: |
7
+ const url = "http://api.example.com"
8
+ expect:
9
+ count: 1
10
+ severity: medium
11
+
12
+ - name: triggers on http URL in typescript
13
+ language: typescript
14
+ code: |
15
+ const url = "http://insecure.example.org/data"
16
+ expect:
17
+ count: 1
18
+ severity: medium
19
+
20
+ - name: triggers on http URL in tsx
21
+ language: tsx
22
+ code: |
23
+ const endpoint = "http://legacy.api.com"
24
+ expect:
25
+ count: 1
26
+ severity: medium
27
+
28
+ - name: triggers on http URL in python
29
+ language: python
30
+ code: |
31
+ url = "http://insecure.example.org/data"
32
+ expect:
33
+ count: 1
34
+ severity: medium
35
+
36
+ - name: triggers on http URL in bash
37
+ language: bash
38
+ code: |
39
+ curl http://api.example.com
40
+ expect:
41
+ count: 1
42
+ severity: medium
43
+
44
+ - name: ignores https URL in javascript
45
+ language: javascript
46
+ code: |
47
+ const url = "https://secure.example.com"
48
+ expect:
49
+ count: 0
50
+
51
+ - name: ignores https URL in typescript
52
+ language: typescript
53
+ code: |
54
+ const url = "https://secure.example.com"
55
+ expect:
56
+ count: 0
57
+
58
+ - name: ignores unrelated string in javascript
59
+ language: javascript
60
+ code: |
61
+ const name = "hello world"
62
+ expect:
63
+ count: 0
64
+
65
+ - name: ignores unrelated string in typescript
66
+ language: typescript
67
+ code: |
68
+ const name = "hello world"
69
+ expect:
70
+ count: 0
71
+
72
+ - name: ignores https URL in bash
73
+ language: bash
74
+ code: |
75
+ curl https://secure.example.com
76
+ expect:
77
+ count: 0
78
+
79
+ - name: triggers on http URL in rust
80
+ language: rust
81
+ code: |
82
+ let url = "http://api.example.com";
83
+ expect:
84
+ count: 1
85
+ severity: medium
86
+
87
+ - name: ignores https URL in rust
88
+ language: rust
89
+ code: |
90
+ let url = "https://secure.example.com";
91
+ expect:
92
+ count: 0
93
+
94
+ - name: triggers on http URL in java
95
+ language: java
96
+ code: |
97
+ class T { String u = "http://api.example.com"; }
98
+ expect:
99
+ count: 1
100
+ severity: medium
101
+
102
+ - name: ignores https URL in java
103
+ language: java
104
+ code: |
105
+ class T { String u = "https://secure.example.com"; }
106
+ expect:
107
+ count: 0
108
+
109
+ - name: triggers on http URL in ruby
110
+ language: ruby
111
+ code: |
112
+ url = "http://api.example.com/data"
113
+ expect:
114
+ count: 1
115
+ severity: medium
@@ -0,0 +1,59 @@
1
+ # source: clean-room
2
+ # licence: MIT
3
+ # vendored-at: 2026-05-20
4
+ # verified-by: Seaworthy team
5
+ # attribution: CWE-319
6
+ id: security.http-no-tls
7
+ severity: medium
8
+ category: security
9
+ min-tier: pro
10
+ languages: [javascript, typescript, tsx, python, bash, rust, java, ruby]
11
+
12
+ copy:
13
+ name-key: checks.http-no-tls.name
14
+ description-key: checks.http-no-tls.description
15
+ message-key: checks.http-no-tls.message
16
+ degraded-key: checks.http-no-tls.degraded
17
+ remediation-key: remediation.security.http-no-tls
18
+
19
+ confidence: medium
20
+
21
+ queries:
22
+ javascript: |
23
+ (string
24
+ (string_fragment) @url
25
+ (#match? @url "^http://")) @match
26
+ typescript: |
27
+ (string
28
+ (string_fragment) @url
29
+ (#match? @url "^http://")) @match
30
+ tsx: |
31
+ (string
32
+ (string_fragment) @url
33
+ (#match? @url "^http://")) @match
34
+ python: |
35
+ (string
36
+ (string_content) @url
37
+ (#match? @url "^http://")) @match
38
+ bash: |
39
+ [
40
+ ((word) @match
41
+ (#match? @match "^http://"))
42
+ (string
43
+ (string_content) @match
44
+ (#match? @match "^http://"))
45
+ ]
46
+ rust: |
47
+ (string_literal) @match
48
+ (#match? @match "^\"http://")
49
+ java: |
50
+ (string_literal
51
+ (string_fragment) @url
52
+ (#match? @url "^http://")) @match
53
+
54
+ ruby: |
55
+ (string
56
+ (string_content) @url
57
+ (#match? @url "^http://")) @match
58
+
59
+ message-captures: [match]
@@ -0,0 +1,188 @@
1
+ rule-id: security.path-traversal
2
+
3
+ cases:
4
+ - name: triggers on fs.readFile with concat in javascript
5
+ language: javascript
6
+ code: |
7
+ const fs = require('fs')
8
+ fs.readFile("/data/" + fileName)
9
+ expect:
10
+ count: 1
11
+ severity: high
12
+
13
+ - name: triggers on fs.writeFile with concat in typescript
14
+ language: typescript
15
+ code: |
16
+ const fs = require('fs')
17
+ fs.writeFile("/tmp/" + userPath, data)
18
+ expect:
19
+ count: 1
20
+ severity: high
21
+
22
+ - name: ignores fs.readFile with plain identifier path in tsx
23
+ language: tsx
24
+ code: |
25
+ import fs from 'fs'
26
+ fs.readFile(userPath)
27
+ expect:
28
+ count: 0
29
+
30
+ - name: triggers on res.sendFile with member expression path
31
+ language: typescript
32
+ code: |
33
+ res.sendFile(req.params.file)
34
+ expect:
35
+ count: 1
36
+ severity: high
37
+
38
+ - name: ignores fs.readFile with CONFIG_PATH constant
39
+ language: typescript
40
+ code: |
41
+ import fs from 'fs'
42
+ const CONFIG_PATH = './data/app-config.json'
43
+ fs.readFileSync(CONFIG_PATH, 'utf8')
44
+ expect:
45
+ count: 0
46
+
47
+ - name: triggers on fs.readFile with template path in tsx
48
+ language: tsx
49
+ code: |
50
+ import fs from 'fs'
51
+ fs.readFile(`/uploads/${name}`)
52
+ expect:
53
+ count: 1
54
+ severity: high
55
+
56
+ - name: triggers on open with concat in python
57
+ language: python
58
+ code: |
59
+ open("/tmp/" + filename)
60
+ expect:
61
+ count: 1
62
+ severity: high
63
+
64
+ - name: ignores open with identifier in python
65
+ language: python
66
+ code: |
67
+ open(user_path)
68
+ expect:
69
+ count: 0
70
+
71
+ - name: triggers on File.read interpolation in ruby
72
+ language: ruby
73
+ code: |
74
+ File.read("/tmp/#{name}")
75
+ expect:
76
+ count: 1
77
+ severity: high
78
+
79
+ - name: ignores safe file read with literal path
80
+ language: javascript
81
+ code: |
82
+ const fs = require('fs')
83
+ fs.readFile("/etc/config.json")
84
+ expect:
85
+ count: 0
86
+
87
+ - name: triggers on unquoted shell file command
88
+ language: bash
89
+ code: |
90
+ cat $USER_PATH
91
+ expect:
92
+ count: 1
93
+ severity: high
94
+
95
+ - name: ignores quoted shell file command
96
+ language: bash
97
+ code: |
98
+ cat "$USER_PATH"
99
+ expect:
100
+ count: 0
101
+
102
+ - name: ignores unrelated code
103
+ language: javascript
104
+ code: |
105
+ const x = "a" + "b"
106
+ expect:
107
+ count: 0
108
+
109
+ - name: triggers on fs.readFile with template path in javascript
110
+ language: javascript
111
+ code: |
112
+ const fs = require('fs')
113
+ fs.readFile(`/tmp/${name}`)
114
+ expect:
115
+ count: 1
116
+ severity: high
117
+
118
+ - name: ignores fs.readFile with path.join in typescript
119
+ language: typescript
120
+ code: |
121
+ import fs from 'fs'
122
+ import * as path from 'path'
123
+ fs.readFile(path.join(baseDir, userFile))
124
+ expect:
125
+ count: 0
126
+
127
+ - name: Juice Shop-style safe fs.writeFile with literal path
128
+ language: javascript
129
+ code: |
130
+ const fs = require('fs')
131
+ fs.writeFile('./data/app-config.json', payload)
132
+ expect:
133
+ count: 0
134
+
135
+ - name: Juice Shop-style codingChallenges read with constant path
136
+ language: typescript
137
+ code: |
138
+ import fs from 'fs'
139
+ export function loadReadme() {
140
+ return fs.readFile('./data/codingchallenges/readme.md')
141
+ }
142
+ expect:
143
+ count: 0
144
+
145
+ - name: triggers on fs File open with field expression in rust
146
+ language: rust
147
+ code: |
148
+ std::fs::File::open(params.filename)
149
+ expect:
150
+ count: 1
151
+ severity: high
152
+
153
+ - name: triggers on fs read_to_string with format macro in rust
154
+ language: rust
155
+ code: |
156
+ std::fs::read_to_string(format!("/tmp/{}", path))
157
+ expect:
158
+ count: 1
159
+ severity: high
160
+
161
+ - name: ignores fs read_to_string with safe identifier in rust
162
+ language: rust
163
+ code: |
164
+ std::fs::read_to_string(canonical)
165
+ expect:
166
+ count: 0
167
+
168
+ - name: ignores fs File open with literal path in rust
169
+ language: rust
170
+ code: |
171
+ std::fs::File::open("/etc/passwd")
172
+ expect:
173
+ count: 0
174
+
175
+ - name: triggers on File concat path in java
176
+ language: java
177
+ code: |
178
+ new File("/data/" + fileName);
179
+ expect:
180
+ count: 1
181
+ severity: high
182
+
183
+ - name: ignores File with identifier only in java
184
+ language: java
185
+ code: |
186
+ new File(userPath);
187
+ expect:
188
+ count: 0