seaworthycode 1.1.2 → 1.2.3
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 +739 -42
- package/dist/index.js.map +1 -1
- package/package.json +14 -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,131 @@
|
|
|
1
|
+
rule-id: data-exposure.hardcoded-ip
|
|
2
|
+
|
|
3
|
+
cases:
|
|
4
|
+
- name: triggers on hardcoded IP in javascript
|
|
5
|
+
language: javascript
|
|
6
|
+
code: |
|
|
7
|
+
const host = "192.168.1.1"
|
|
8
|
+
expect:
|
|
9
|
+
count: 1
|
|
10
|
+
severity: low
|
|
11
|
+
|
|
12
|
+
- name: triggers on hardcoded IP in typescript
|
|
13
|
+
language: typescript
|
|
14
|
+
code: |
|
|
15
|
+
const host = "10.0.0.1"
|
|
16
|
+
expect:
|
|
17
|
+
count: 1
|
|
18
|
+
severity: low
|
|
19
|
+
|
|
20
|
+
- name: triggers on hardcoded IP in tsx
|
|
21
|
+
language: tsx
|
|
22
|
+
code: |
|
|
23
|
+
const server = "172.16.0.1"
|
|
24
|
+
expect:
|
|
25
|
+
count: 1
|
|
26
|
+
severity: low
|
|
27
|
+
|
|
28
|
+
- name: triggers on hardcoded IP in python
|
|
29
|
+
language: python
|
|
30
|
+
code: |
|
|
31
|
+
host = "10.0.0.1"
|
|
32
|
+
expect:
|
|
33
|
+
count: 1
|
|
34
|
+
severity: low
|
|
35
|
+
|
|
36
|
+
- name: triggers on hardcoded IP in bash
|
|
37
|
+
language: bash
|
|
38
|
+
code: |
|
|
39
|
+
curl http://10.0.0.1:8080/health
|
|
40
|
+
expect:
|
|
41
|
+
count: 1
|
|
42
|
+
severity: low
|
|
43
|
+
|
|
44
|
+
- name: ignores non-IP string
|
|
45
|
+
language: javascript
|
|
46
|
+
code: |
|
|
47
|
+
const version = "1.2.3"
|
|
48
|
+
expect:
|
|
49
|
+
count: 0
|
|
50
|
+
|
|
51
|
+
- name: ignores non-IP string in typescript
|
|
52
|
+
language: typescript
|
|
53
|
+
code: |
|
|
54
|
+
const version = "1.2.3"
|
|
55
|
+
expect:
|
|
56
|
+
count: 0
|
|
57
|
+
|
|
58
|
+
- name: ignores safe code
|
|
59
|
+
language: python
|
|
60
|
+
code: |
|
|
61
|
+
host = "localhost"
|
|
62
|
+
expect:
|
|
63
|
+
count: 0
|
|
64
|
+
|
|
65
|
+
- name: ignores hostname in bash
|
|
66
|
+
language: bash
|
|
67
|
+
code: |
|
|
68
|
+
curl https://api.example.com
|
|
69
|
+
expect:
|
|
70
|
+
count: 0
|
|
71
|
+
|
|
72
|
+
- name: triggers on hardcoded IP in rust
|
|
73
|
+
language: rust
|
|
74
|
+
code: |
|
|
75
|
+
let host = "192.168.1.1"
|
|
76
|
+
expect:
|
|
77
|
+
count: 1
|
|
78
|
+
severity: low
|
|
79
|
+
|
|
80
|
+
- name: ignores hostname in rust
|
|
81
|
+
language: rust
|
|
82
|
+
code: |
|
|
83
|
+
let host = "localhost"
|
|
84
|
+
expect:
|
|
85
|
+
count: 0
|
|
86
|
+
|
|
87
|
+
- name: triggers on hardcoded IP in html attribute
|
|
88
|
+
language: html
|
|
89
|
+
code: |
|
|
90
|
+
<a href="http://192.168.1.1/api">Link</a>
|
|
91
|
+
expect:
|
|
92
|
+
count: 1
|
|
93
|
+
severity: low
|
|
94
|
+
|
|
95
|
+
- name: triggers on hardcoded IP in css url
|
|
96
|
+
language: css
|
|
97
|
+
code: |
|
|
98
|
+
@import url("http://10.0.0.1/style.css");
|
|
99
|
+
expect:
|
|
100
|
+
count: 1
|
|
101
|
+
severity: low
|
|
102
|
+
|
|
103
|
+
- name: ignores html attribute without IP
|
|
104
|
+
language: html
|
|
105
|
+
code: |
|
|
106
|
+
<a href="https://example.com">Link</a>
|
|
107
|
+
expect:
|
|
108
|
+
count: 0
|
|
109
|
+
|
|
110
|
+
- name: ignores css url without IP
|
|
111
|
+
language: css
|
|
112
|
+
code: |
|
|
113
|
+
@import url("https://example.com/style.css");
|
|
114
|
+
expect:
|
|
115
|
+
count: 0
|
|
116
|
+
|
|
117
|
+
- name: triggers on hardcoded IP in java
|
|
118
|
+
language: java
|
|
119
|
+
code: |
|
|
120
|
+
class T { String host = "192.168.1.1"; }
|
|
121
|
+
expect:
|
|
122
|
+
count: 1
|
|
123
|
+
severity: low
|
|
124
|
+
|
|
125
|
+
- name: triggers on hardcoded IP in ruby
|
|
126
|
+
language: ruby
|
|
127
|
+
code: |
|
|
128
|
+
host = "10.0.0.1"
|
|
129
|
+
expect:
|
|
130
|
+
count: 1
|
|
131
|
+
severity: low
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# source: clean-room
|
|
2
|
+
# licence: MIT
|
|
3
|
+
# vendored-at: 2026-05-20
|
|
4
|
+
# verified-by: Seaworthy team
|
|
5
|
+
# attribution: CWE-200
|
|
6
|
+
id: data-exposure.hardcoded-ip
|
|
7
|
+
severity: low
|
|
8
|
+
category: data-exposure
|
|
9
|
+
min-tier: pro
|
|
10
|
+
languages: [javascript, typescript, tsx, python, bash, rust, java, html, css, ruby]
|
|
11
|
+
|
|
12
|
+
copy:
|
|
13
|
+
name-key: checks.hardcoded-ip.name
|
|
14
|
+
description-key: checks.hardcoded-ip.description
|
|
15
|
+
message-key: checks.hardcoded-ip.message
|
|
16
|
+
degraded-key: checks.hardcoded-ip.degraded
|
|
17
|
+
remediation-key: remediation.data-exposure.hardcoded-ip
|
|
18
|
+
|
|
19
|
+
confidence: low
|
|
20
|
+
|
|
21
|
+
queries:
|
|
22
|
+
javascript: |
|
|
23
|
+
(string
|
|
24
|
+
(string_fragment) @ip
|
|
25
|
+
(#match? @ip "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")) @match
|
|
26
|
+
typescript: |
|
|
27
|
+
(string
|
|
28
|
+
(string_fragment) @ip
|
|
29
|
+
(#match? @ip "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")) @match
|
|
30
|
+
tsx: |
|
|
31
|
+
(string
|
|
32
|
+
(string_fragment) @ip
|
|
33
|
+
(#match? @ip "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")) @match
|
|
34
|
+
python: |
|
|
35
|
+
(string
|
|
36
|
+
(string_content) @ip
|
|
37
|
+
(#match? @ip "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")) @match
|
|
38
|
+
bash: |
|
|
39
|
+
[
|
|
40
|
+
((word) @match
|
|
41
|
+
(#match? @match "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"))
|
|
42
|
+
(string
|
|
43
|
+
(string_content) @match
|
|
44
|
+
(#match? @match "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"))
|
|
45
|
+
]
|
|
46
|
+
rust: |
|
|
47
|
+
(string_literal) @match
|
|
48
|
+
(#match? @match "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")
|
|
49
|
+
html: |
|
|
50
|
+
(attribute
|
|
51
|
+
(quoted_attribute_value
|
|
52
|
+
(attribute_value) @match)
|
|
53
|
+
(#match? @match "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"))
|
|
54
|
+
css: |
|
|
55
|
+
(string_value) @match
|
|
56
|
+
(#match? @match "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")
|
|
57
|
+
java: |
|
|
58
|
+
(string_literal
|
|
59
|
+
(string_fragment) @ip
|
|
60
|
+
(#match? @ip "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")) @match
|
|
61
|
+
|
|
62
|
+
ruby: |
|
|
63
|
+
(string
|
|
64
|
+
(string_content) @ip
|
|
65
|
+
(#match? @ip "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")) @match
|
|
66
|
+
|
|
67
|
+
message-captures: [match]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
rule-id: data-exposure.localstorage-sensitive-data
|
|
2
|
+
|
|
3
|
+
cases:
|
|
4
|
+
- name: triggers on password in localStorage in javascript
|
|
5
|
+
language: javascript
|
|
6
|
+
code: |
|
|
7
|
+
localStorage.setItem('password', userPassword);
|
|
8
|
+
expect:
|
|
9
|
+
count: 1
|
|
10
|
+
severity: medium
|
|
11
|
+
|
|
12
|
+
- name: triggers on token in localStorage in typescript
|
|
13
|
+
language: typescript
|
|
14
|
+
code: |
|
|
15
|
+
localStorage.setItem('auth_token', token);
|
|
16
|
+
expect:
|
|
17
|
+
count: 1
|
|
18
|
+
severity: medium
|
|
19
|
+
|
|
20
|
+
- name: triggers on password in localStorage in tsx
|
|
21
|
+
language: tsx
|
|
22
|
+
code: |
|
|
23
|
+
export default function Settings() {
|
|
24
|
+
localStorage.setItem("password", key);
|
|
25
|
+
return <div />;
|
|
26
|
+
}
|
|
27
|
+
expect:
|
|
28
|
+
count: 1
|
|
29
|
+
severity: medium
|
|
30
|
+
|
|
31
|
+
- name: ignores safe keys
|
|
32
|
+
language: javascript
|
|
33
|
+
code: |
|
|
34
|
+
localStorage.setItem('theme', 'dark');
|
|
35
|
+
expect:
|
|
36
|
+
count: 0
|
|
37
|
+
|
|
38
|
+
- name: ignores safe keys in typescript
|
|
39
|
+
language: typescript
|
|
40
|
+
code: |
|
|
41
|
+
localStorage.setItem('theme', 'dark');
|
|
42
|
+
expect:
|
|
43
|
+
count: 0
|
|
44
|
+
|
|
45
|
+
- name: triggers on password in localStorage in html script
|
|
46
|
+
language: html
|
|
47
|
+
code: |
|
|
48
|
+
<script>localStorage.setItem('password', userPassword);</script>
|
|
49
|
+
expect:
|
|
50
|
+
count: 1
|
|
51
|
+
severity: medium
|
|
52
|
+
|
|
53
|
+
- name: ignores safe keys in html script
|
|
54
|
+
language: html
|
|
55
|
+
code: |
|
|
56
|
+
<script>localStorage.setItem('theme', 'dark');</script>
|
|
57
|
+
expect:
|
|
58
|
+
count: 0
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# source: clean-room
|
|
2
|
+
# licence: MIT
|
|
3
|
+
# vendored-at: 2026-05-20
|
|
4
|
+
# verified-by: andy
|
|
5
|
+
# attribution: CWE-312
|
|
6
|
+
id: data-exposure.localstorage-sensitive-data
|
|
7
|
+
severity: medium
|
|
8
|
+
category: data-exposure
|
|
9
|
+
min-tier: pro
|
|
10
|
+
languages: [javascript, typescript, tsx, html]
|
|
11
|
+
|
|
12
|
+
copy:
|
|
13
|
+
name-key: checks.localstorage-sensitive-data.name
|
|
14
|
+
description-key: checks.localstorage-sensitive-data.description
|
|
15
|
+
message-key: checks.localstorage-sensitive-data.message
|
|
16
|
+
degraded-key: checks.localstorage-sensitive-data.degraded
|
|
17
|
+
remediation-key: remediation.data-exposure.localstorage-sensitive-data
|
|
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
|
+
arguments: (arguments
|
|
28
|
+
(string
|
|
29
|
+
(string_fragment) @key))
|
|
30
|
+
(#eq? @obj "localStorage")
|
|
31
|
+
(#eq? @method "setItem")
|
|
32
|
+
(#match? @key "(password|token|secret|api[_-]?key|auth)")) @match
|
|
33
|
+
typescript: |
|
|
34
|
+
(call_expression
|
|
35
|
+
function: (member_expression
|
|
36
|
+
object: (identifier) @obj
|
|
37
|
+
property: (property_identifier) @method)
|
|
38
|
+
arguments: (arguments
|
|
39
|
+
(string
|
|
40
|
+
(string_fragment) @key))
|
|
41
|
+
(#eq? @obj "localStorage")
|
|
42
|
+
(#eq? @method "setItem")
|
|
43
|
+
(#match? @key "(password|token|secret|api[_-]?key|auth)")) @match
|
|
44
|
+
tsx: |
|
|
45
|
+
(call_expression
|
|
46
|
+
function: (member_expression
|
|
47
|
+
object: (identifier) @obj
|
|
48
|
+
property: (property_identifier) @method)
|
|
49
|
+
arguments: (arguments
|
|
50
|
+
(string
|
|
51
|
+
(string_fragment) @key))
|
|
52
|
+
(#eq? @obj "localStorage")
|
|
53
|
+
(#eq? @method "setItem")
|
|
54
|
+
(#match? @key "(password|token|secret|api[_-]?key|auth)")) @match
|
|
55
|
+
html: |
|
|
56
|
+
(script_element
|
|
57
|
+
(raw_text) @match
|
|
58
|
+
(#match? @match "localStorage\\.setItem.*(password|token|secret|api[_-]?key|auth)"))
|
|
59
|
+
|
|
60
|
+
message-captures: [match]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
rule-id: dependencies.deprecated-functions
|
|
2
|
+
|
|
3
|
+
cases:
|
|
4
|
+
- name: triggers on assert.equal in javascript
|
|
5
|
+
language: javascript
|
|
6
|
+
code: |
|
|
7
|
+
assert.equal(1, 2)
|
|
8
|
+
expect:
|
|
9
|
+
count: 1
|
|
10
|
+
severity: low
|
|
11
|
+
|
|
12
|
+
- name: triggers on assert.equal in typescript
|
|
13
|
+
language: typescript
|
|
14
|
+
code: |
|
|
15
|
+
assert.equal(x, y)
|
|
16
|
+
expect:
|
|
17
|
+
count: 1
|
|
18
|
+
severity: low
|
|
19
|
+
|
|
20
|
+
- name: triggers on assert.equal in tsx
|
|
21
|
+
language: tsx
|
|
22
|
+
code: |
|
|
23
|
+
assert.equal(data, expected)
|
|
24
|
+
expect:
|
|
25
|
+
count: 1
|
|
26
|
+
severity: low
|
|
27
|
+
|
|
28
|
+
- name: ignores assert.strictEqual
|
|
29
|
+
language: javascript
|
|
30
|
+
code: |
|
|
31
|
+
assert.strictEqual(1, 1)
|
|
32
|
+
expect:
|
|
33
|
+
count: 0
|
|
34
|
+
|
|
35
|
+
- name: ignores assert.strictEqual in typescript
|
|
36
|
+
language: typescript
|
|
37
|
+
code: |
|
|
38
|
+
assert.strictEqual(1, 1)
|
|
39
|
+
expect:
|
|
40
|
+
count: 0
|
|
41
|
+
|
|
42
|
+
- name: triggers on import of deprecated imp module in python
|
|
43
|
+
language: python
|
|
44
|
+
code: |
|
|
45
|
+
import imp
|
|
46
|
+
expect:
|
|
47
|
+
count: 1
|
|
48
|
+
severity: low
|
|
49
|
+
- name: triggers on import of deprecated cgi module in python
|
|
50
|
+
language: python
|
|
51
|
+
code: |
|
|
52
|
+
from cgi import parse_header
|
|
53
|
+
expect:
|
|
54
|
+
count: 1
|
|
55
|
+
severity: low
|
|
56
|
+
- name: ignores import of non-deprecated module in python
|
|
57
|
+
language: python
|
|
58
|
+
code: |
|
|
59
|
+
import json
|
|
60
|
+
expect:
|
|
61
|
+
count: 0
|
|
62
|
+
|
|
63
|
+
- name: triggers on deprecated try macro in rust
|
|
64
|
+
language: rust
|
|
65
|
+
code: |
|
|
66
|
+
let x = try!(foo());
|
|
67
|
+
expect:
|
|
68
|
+
count: 1
|
|
69
|
+
severity: low
|
|
70
|
+
|
|
71
|
+
- name: ignores normal function in rust
|
|
72
|
+
language: rust
|
|
73
|
+
code: |
|
|
74
|
+
fn new() {}
|
|
75
|
+
expect:
|
|
76
|
+
count: 0
|
|
77
|
+
|
|
78
|
+
- name: triggers on Thread.stop in java
|
|
79
|
+
language: java
|
|
80
|
+
code: |
|
|
81
|
+
class T { void f(Thread t) { t.stop(); } }
|
|
82
|
+
expect:
|
|
83
|
+
count: 1
|
|
84
|
+
severity: low
|
|
85
|
+
|
|
86
|
+
- name: triggers on URI.escape in ruby
|
|
87
|
+
language: ruby
|
|
88
|
+
code: |
|
|
89
|
+
URI.escape("a b")
|
|
90
|
+
expect:
|
|
91
|
+
count: 1
|
|
92
|
+
severity: low
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# source: clean-room
|
|
2
|
+
# licence: MIT
|
|
3
|
+
# vendored-at: 2026-05-20
|
|
4
|
+
# verified-by: Seaworthy team
|
|
5
|
+
# attribution: CWE-477
|
|
6
|
+
id: dependencies.deprecated-functions
|
|
7
|
+
severity: low
|
|
8
|
+
category: dependencies
|
|
9
|
+
min-tier: pro
|
|
10
|
+
languages: [javascript, typescript, tsx, python, rust, java, ruby]
|
|
11
|
+
|
|
12
|
+
copy:
|
|
13
|
+
name-key: checks.deprecated-functions.name
|
|
14
|
+
description-key: checks.deprecated-functions.description
|
|
15
|
+
message-key: checks.deprecated-functions.message
|
|
16
|
+
degraded-key: checks.deprecated-functions.degraded
|
|
17
|
+
remediation-key: remediation.dependencies.deprecated-functions
|
|
18
|
+
|
|
19
|
+
confidence: medium
|
|
20
|
+
|
|
21
|
+
queries:
|
|
22
|
+
javascript: |
|
|
23
|
+
(call_expression
|
|
24
|
+
function: (member_expression
|
|
25
|
+
object: (identifier) @obj
|
|
26
|
+
property: (property_identifier) @method)
|
|
27
|
+
(#eq? @obj "assert")
|
|
28
|
+
(#eq? @method "equal")) @match
|
|
29
|
+
typescript: |
|
|
30
|
+
(call_expression
|
|
31
|
+
function: (member_expression
|
|
32
|
+
object: (identifier) @obj
|
|
33
|
+
property: (property_identifier) @method)
|
|
34
|
+
(#eq? @obj "assert")
|
|
35
|
+
(#eq? @method "equal")) @match
|
|
36
|
+
tsx: |
|
|
37
|
+
(call_expression
|
|
38
|
+
function: (member_expression
|
|
39
|
+
object: (identifier) @obj
|
|
40
|
+
property: (property_identifier) @method)
|
|
41
|
+
(#eq? @obj "assert")
|
|
42
|
+
(#eq? @method "equal")) @match
|
|
43
|
+
python: |
|
|
44
|
+
[
|
|
45
|
+
(import_statement
|
|
46
|
+
name: (dotted_name) @mod
|
|
47
|
+
(#match? @mod "^(imp|cgi)$"))
|
|
48
|
+
(import_from_statement
|
|
49
|
+
module_name: (dotted_name) @mod
|
|
50
|
+
(#match? @mod "^(imp|cgi)$"))
|
|
51
|
+
] @match
|
|
52
|
+
rust: |
|
|
53
|
+
(macro_invocation
|
|
54
|
+
(identifier) @name
|
|
55
|
+
(#eq? @name "try")) @match
|
|
56
|
+
java: |
|
|
57
|
+
(method_invocation
|
|
58
|
+
name: (identifier) @method
|
|
59
|
+
(#eq? @method "stop")) @match
|
|
60
|
+
|
|
61
|
+
ruby: |
|
|
62
|
+
(call
|
|
63
|
+
receiver: (constant) @recv (#eq? @recv "URI")
|
|
64
|
+
method: (identifier) @method (#eq? @method "escape")) @match
|
|
65
|
+
|
|
66
|
+
message-captures: [match]
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
rule-id: ops.hardcoded-port
|
|
2
|
+
|
|
3
|
+
cases:
|
|
4
|
+
- name: triggers on app.listen with literal port in javascript
|
|
5
|
+
language: javascript
|
|
6
|
+
code: |
|
|
7
|
+
app.listen(3000)
|
|
8
|
+
expect:
|
|
9
|
+
count: 1
|
|
10
|
+
severity: low
|
|
11
|
+
|
|
12
|
+
- name: triggers on app.listen with literal port in typescript
|
|
13
|
+
language: typescript
|
|
14
|
+
code: |
|
|
15
|
+
app.listen(8080)
|
|
16
|
+
expect:
|
|
17
|
+
count: 1
|
|
18
|
+
severity: low
|
|
19
|
+
|
|
20
|
+
- name: triggers on app.listen with literal port in tsx
|
|
21
|
+
language: tsx
|
|
22
|
+
code: |
|
|
23
|
+
app.listen(9000)
|
|
24
|
+
expect:
|
|
25
|
+
count: 1
|
|
26
|
+
severity: low
|
|
27
|
+
|
|
28
|
+
- name: ignores app.listen with environment variable
|
|
29
|
+
language: tsx
|
|
30
|
+
code: |
|
|
31
|
+
app.listen(process.env.PORT)
|
|
32
|
+
expect:
|
|
33
|
+
count: 0
|
|
34
|
+
|
|
35
|
+
- name: ignores unrelated listen
|
|
36
|
+
language: javascript
|
|
37
|
+
code: |
|
|
38
|
+
server.listen(3000)
|
|
39
|
+
expect:
|
|
40
|
+
count: 0
|
|
41
|
+
|
|
42
|
+
- name: ignores unrelated listen in typescript
|
|
43
|
+
language: typescript
|
|
44
|
+
code: |
|
|
45
|
+
server.listen(3000)
|
|
46
|
+
expect:
|
|
47
|
+
count: 0
|
|
48
|
+
|
|
49
|
+
- name: triggers on app.run with literal port in python
|
|
50
|
+
language: python
|
|
51
|
+
code: |
|
|
52
|
+
app.run(port=5000)
|
|
53
|
+
expect:
|
|
54
|
+
count: 1
|
|
55
|
+
severity: low
|
|
56
|
+
- name: triggers on hardcoded port in bash URL
|
|
57
|
+
language: bash
|
|
58
|
+
code: |
|
|
59
|
+
curl http://localhost:8080/health
|
|
60
|
+
expect:
|
|
61
|
+
count: 1
|
|
62
|
+
severity: low
|
|
63
|
+
- name: ignores app.run with env variable port in python
|
|
64
|
+
language: python
|
|
65
|
+
code: |
|
|
66
|
+
app.run(port=os.environ.get("PORT"))
|
|
67
|
+
expect:
|
|
68
|
+
count: 0
|
|
69
|
+
- name: ignores unrelated python call
|
|
70
|
+
language: python
|
|
71
|
+
code: |
|
|
72
|
+
print("hello")
|
|
73
|
+
expect:
|
|
74
|
+
count: 0
|
|
75
|
+
- name: ignores bash URL without explicit port
|
|
76
|
+
language: bash
|
|
77
|
+
code: |
|
|
78
|
+
curl https://example.com/health
|
|
79
|
+
expect:
|
|
80
|
+
count: 0
|
|
81
|
+
|
|
82
|
+
- name: triggers on hardcoded port in rust
|
|
83
|
+
language: rust
|
|
84
|
+
code: |
|
|
85
|
+
server.bind("127.0.0.1:8080")
|
|
86
|
+
expect:
|
|
87
|
+
count: 1
|
|
88
|
+
severity: low
|
|
89
|
+
|
|
90
|
+
- name: ignores bind without explicit port in rust
|
|
91
|
+
language: rust
|
|
92
|
+
code: |
|
|
93
|
+
server.bind("127.0.0.1")
|
|
94
|
+
expect:
|
|
95
|
+
count: 0
|
|
96
|
+
|
|
97
|
+
- name: triggers on hardcoded port in html attribute
|
|
98
|
+
language: html
|
|
99
|
+
code: |
|
|
100
|
+
<a href="http://localhost:8080/api">Link</a>
|
|
101
|
+
expect:
|
|
102
|
+
count: 1
|
|
103
|
+
severity: low
|
|
104
|
+
|
|
105
|
+
- name: triggers on hardcoded port in css url
|
|
106
|
+
language: css
|
|
107
|
+
code: |
|
|
108
|
+
@import url("http://localhost:3000/style.css");
|
|
109
|
+
expect:
|
|
110
|
+
count: 1
|
|
111
|
+
severity: low
|
|
112
|
+
|
|
113
|
+
- name: ignores html attribute without explicit port
|
|
114
|
+
language: html
|
|
115
|
+
code: |
|
|
116
|
+
<a href="https://example.com">Link</a>
|
|
117
|
+
expect:
|
|
118
|
+
count: 0
|
|
119
|
+
|
|
120
|
+
- name: ignores css url without explicit port
|
|
121
|
+
language: css
|
|
122
|
+
code: |
|
|
123
|
+
@import url("https://example.com/style.css");
|
|
124
|
+
expect:
|
|
125
|
+
count: 0
|
|
126
|
+
|
|
127
|
+
- name: triggers on server.port in java properties string
|
|
128
|
+
language: java
|
|
129
|
+
code: |
|
|
130
|
+
class T { String p = "server.port=8080"; }
|
|
131
|
+
expect:
|
|
132
|
+
count: 1
|
|
133
|
+
severity: low
|
|
134
|
+
|
|
135
|
+
- name: triggers on hardcoded port in ruby URL string
|
|
136
|
+
language: ruby
|
|
137
|
+
code: |
|
|
138
|
+
url = "http://localhost:3000/api"
|
|
139
|
+
expect:
|
|
140
|
+
count: 1
|
|
141
|
+
severity: low
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# source: clean-room
|
|
2
|
+
# licence: MIT
|
|
3
|
+
# vendored-at: 2026-05-20
|
|
4
|
+
# verified-by: Seaworthy team
|
|
5
|
+
# attribution: CWE-779
|
|
6
|
+
id: ops.hardcoded-port
|
|
7
|
+
severity: low
|
|
8
|
+
category: ops
|
|
9
|
+
min-tier: pro
|
|
10
|
+
languages: [javascript, typescript, tsx, python, bash, rust, java, html, css, ruby]
|
|
11
|
+
|
|
12
|
+
copy:
|
|
13
|
+
name-key: checks.hardcoded-port.name
|
|
14
|
+
description-key: checks.hardcoded-port.description
|
|
15
|
+
message-key: checks.hardcoded-port.message
|
|
16
|
+
degraded-key: checks.hardcoded-port.degraded
|
|
17
|
+
remediation-key: remediation.ops.hardcoded-port
|
|
18
|
+
|
|
19
|
+
confidence: low
|
|
20
|
+
|
|
21
|
+
queries:
|
|
22
|
+
javascript: |
|
|
23
|
+
(call_expression
|
|
24
|
+
function: (member_expression
|
|
25
|
+
object: (identifier) @obj
|
|
26
|
+
property: (property_identifier) @method)
|
|
27
|
+
arguments: (arguments (number))
|
|
28
|
+
(#eq? @obj "app")
|
|
29
|
+
(#eq? @method "listen")) @match
|
|
30
|
+
typescript: |
|
|
31
|
+
(call_expression
|
|
32
|
+
function: (member_expression
|
|
33
|
+
object: (identifier) @obj
|
|
34
|
+
property: (property_identifier) @method)
|
|
35
|
+
arguments: (arguments (number))
|
|
36
|
+
(#eq? @obj "app")
|
|
37
|
+
(#eq? @method "listen")) @match
|
|
38
|
+
tsx: |
|
|
39
|
+
(call_expression
|
|
40
|
+
function: (member_expression
|
|
41
|
+
object: (identifier) @obj
|
|
42
|
+
property: (property_identifier) @method)
|
|
43
|
+
arguments: (arguments (number))
|
|
44
|
+
(#eq? @obj "app")
|
|
45
|
+
(#eq? @method "listen")) @match
|
|
46
|
+
python: |
|
|
47
|
+
(call
|
|
48
|
+
function: (attribute
|
|
49
|
+
object: (identifier) @obj
|
|
50
|
+
attribute: (identifier) @method)
|
|
51
|
+
arguments: (argument_list
|
|
52
|
+
(keyword_argument
|
|
53
|
+
name: (identifier) @key
|
|
54
|
+
value: (integer) @val))
|
|
55
|
+
(#eq? @method "run")
|
|
56
|
+
(#eq? @key "port")) @match
|
|
57
|
+
bash: |
|
|
58
|
+
[
|
|
59
|
+
((word) @match
|
|
60
|
+
(#match? @match ":(3000|5000|8000|8080|9000)(/|$)"))
|
|
61
|
+
(string
|
|
62
|
+
(string_content) @match
|
|
63
|
+
(#match? @match ":(3000|5000|8000|8080|9000)(/|$)"))
|
|
64
|
+
]
|
|
65
|
+
rust: |
|
|
66
|
+
(call_expression
|
|
67
|
+
function: (field_expression
|
|
68
|
+
field: (field_identifier) @func
|
|
69
|
+
(#eq? @func "bind"))
|
|
70
|
+
arguments: (arguments
|
|
71
|
+
(string_literal) @addr
|
|
72
|
+
(#match? @addr ":[0-9]+"))) @match
|
|
73
|
+
html: |
|
|
74
|
+
(attribute
|
|
75
|
+
(quoted_attribute_value
|
|
76
|
+
(attribute_value) @match)
|
|
77
|
+
(#match? @match ":(3000|5000|8000|8080|9000)(/|$)"))
|
|
78
|
+
css: |
|
|
79
|
+
(string_value) @match
|
|
80
|
+
(#match? @match ":(3000|5000|8000|8080|9000)(/|$)")
|
|
81
|
+
java: |
|
|
82
|
+
(string_literal
|
|
83
|
+
(string_fragment) @match
|
|
84
|
+
(#match? @match "server\\.port=(3000|5000|8000|8080|9000)"))
|
|
85
|
+
|
|
86
|
+
ruby: |
|
|
87
|
+
(string
|
|
88
|
+
(string_content) @match
|
|
89
|
+
(#match? @match ":(3000|5000|8000|8080|9000)(/|$)"))
|
|
90
|
+
|
|
91
|
+
message-captures: [match]
|