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
package/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "seaworthycode",
3
- "version": "1.1.1",
3
+ "version": "1.1.4",
4
4
  "type": "module",
5
5
  "files": [
6
- "dist"
6
+ "dist",
7
+ "rules",
8
+ "wasm"
7
9
  ],
8
10
  "bin": {
9
11
  "seaworthy": "./dist/index.js"
@@ -14,15 +16,9 @@
14
16
  "import": "./dist/index.js"
15
17
  }
16
18
  },
17
- "scripts": {
18
- "build": "tsup",
19
- "dev": "tsup --watch",
20
- "lint": "eslint src/",
21
- "check-types": "tsc --noEmit",
22
- "test": "vitest run"
23
- },
24
19
  "dependencies": {
25
20
  "@anthropic-ai/sdk": "^0.91.1",
21
+ "@clack/prompts": "1.5.1",
26
22
  "acorn": "^8.16.0",
27
23
  "acorn-walk": "^8.3.5",
28
24
  "cac": "^7.0.0",
@@ -37,10 +33,18 @@
37
33
  "zod": "^4.4.3"
38
34
  },
39
35
  "devDependencies": {
40
- "eslint": "^9.39.4",
41
36
  "@types/node": "^22.10.5",
37
+ "eslint": "^9.39.4",
42
38
  "tsup": "^8.3.6",
43
39
  "typescript": "^5.7.3",
44
- "vitest": "^4.1.0"
40
+ "vitest": "^4.1.0",
41
+ "@seaworthy/core": "0.0.0"
42
+ },
43
+ "scripts": {
44
+ "build": "tsup",
45
+ "dev": "tsup --watch",
46
+ "lint": "eslint src/",
47
+ "check-types": "tsc --noEmit",
48
+ "test": "vitest run"
45
49
  }
46
- }
50
+ }
@@ -0,0 +1,114 @@
1
+ rule-id: configuration.insecure-cookie-flags
2
+
3
+ cases:
4
+ - name: triggers on res.cookie in javascript
5
+ language: javascript
6
+ code: |
7
+ res.cookie("session", "abc123")
8
+ expect:
9
+ count: 1
10
+ severity: medium
11
+
12
+ - name: triggers on res.cookie in typescript
13
+ language: typescript
14
+ code: |
15
+ res.cookie("token", jwtToken)
16
+ expect:
17
+ count: 1
18
+ severity: medium
19
+
20
+ - name: triggers on res.cookie in tsx
21
+ language: tsx
22
+ code: |
23
+ res.cookie("auth", "token123")
24
+ expect:
25
+ count: 1
26
+ severity: medium
27
+
28
+ - name: ignores fully secured res.cookie in javascript
29
+ language: javascript
30
+ code: |
31
+ res.cookie("session", "abc123", { secure: true, httpOnly: true, sameSite: "Strict" })
32
+ expect:
33
+ count: 0
34
+
35
+ - name: ignores fully secured res.cookie in typescript
36
+ language: typescript
37
+ code: |
38
+ res.cookie("session", "abc123", { secure: true, httpOnly: true, sameSite: "Strict" })
39
+ expect:
40
+ count: 0
41
+
42
+ - name: triggers when some cookie flags are still missing
43
+ language: javascript
44
+ code: |
45
+ res.cookie("session", "abc123", { secure: true })
46
+ expect:
47
+ count: 1
48
+ severity: medium
49
+
50
+ - name: triggers on set_cookie in python
51
+ language: python
52
+ code: |
53
+ response.set_cookie("auth", "value")
54
+ expect:
55
+ count: 1
56
+ severity: medium
57
+
58
+ - name: ignores fully secured set_cookie in python
59
+ language: python
60
+ code: |
61
+ response.set_cookie("auth", "value", secure=True, httponly=True, samesite="Lax")
62
+ expect:
63
+ count: 0
64
+
65
+ - name: ignores unrelated response method
66
+ language: javascript
67
+ code: |
68
+ res.send("ok")
69
+ expect:
70
+ count: 0
71
+
72
+ - name: ignores unrelated response method in typescript
73
+ language: typescript
74
+ code: |
75
+ res.send("ok")
76
+ expect:
77
+ count: 0
78
+
79
+ - name: ignores unrelated python code
80
+ language: python
81
+ code: |
82
+ x = 1 + 2
83
+ expect:
84
+ count: 0
85
+
86
+ - name: triggers on setSecure false in java
87
+ language: java
88
+ code: |
89
+ cookie.setSecure(false);
90
+ expect:
91
+ count: 1
92
+ severity: medium
93
+
94
+ - name: triggers on addCookie with new Cookie in java
95
+ language: java
96
+ code: |
97
+ response.addCookie(new Cookie("session", token));
98
+ expect:
99
+ count: 1
100
+ severity: medium
101
+
102
+ - name: ignores unrelated java code
103
+ language: java
104
+ code: |
105
+ System.out.println("ok");
106
+ expect:
107
+ count: 0
108
+
109
+ - name: triggers on cookies assignment without secure flags in ruby
110
+ language: ruby
111
+ code: |
112
+ cookies[:session_id] = user.id
113
+ expect:
114
+ count: 1
@@ -0,0 +1,77 @@
1
+ # source: clean-room
2
+ # licence: MIT
3
+ # vendored-at: 2026-05-20
4
+ # verified-by: Seaworthy team
5
+ # attribution: CWE-614
6
+ id: configuration.insecure-cookie-flags
7
+ severity: medium
8
+ category: configuration
9
+ min-tier: pro
10
+ languages: [javascript, typescript, tsx, python, java, ruby]
11
+
12
+ copy:
13
+ name-key: checks.insecure-cookie-flags.name
14
+ description-key: checks.insecure-cookie-flags.description
15
+ message-key: checks.insecure-cookie-flags.message
16
+ degraded-key: checks.insecure-cookie-flags.degraded
17
+ remediation-key: remediation.configuration.insecure-cookie-flags
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 "res")
28
+ (#eq? @method "cookie")) @match
29
+ (#not-match? @match "(?=.*secure\\s*:\\s*true)(?=.*httpOnly\\s*:\\s*true)(?=.*sameSite\\s*:\\s*(\"Strict\"|\"Lax\"|'Strict'|'Lax'))"))
30
+ typescript: |
31
+ ((call_expression
32
+ function: (member_expression
33
+ object: (identifier) @obj
34
+ property: (property_identifier) @method)
35
+ (#eq? @obj "res")
36
+ (#eq? @method "cookie")) @match
37
+ (#not-match? @match "(?=.*secure\\s*:\\s*true)(?=.*httpOnly\\s*:\\s*true)(?=.*sameSite\\s*:\\s*(\"Strict\"|\"Lax\"|'Strict'|'Lax'))"))
38
+ tsx: |
39
+ ((call_expression
40
+ function: (member_expression
41
+ object: (identifier) @obj
42
+ property: (property_identifier) @method)
43
+ (#eq? @obj "res")
44
+ (#eq? @method "cookie")) @match
45
+ (#not-match? @match "(?=.*secure\\s*:\\s*true)(?=.*httpOnly\\s*:\\s*true)(?=.*sameSite\\s*:\\s*(\"Strict\"|\"Lax\"|'Strict'|'Lax'))"))
46
+ python: |
47
+ ((call
48
+ function: (attribute
49
+ object: (identifier) @obj
50
+ attribute: (identifier) @method)
51
+ (#eq? @obj "response")
52
+ (#eq? @method "set_cookie")) @match
53
+ (#not-match? @match "(?=.*secure\\s*=\\s*True)(?=.*httponly\\s*=\\s*True)(?=.*samesite\\s*=\\s*(\"Strict\"|\"Lax\"|'Strict'|'Lax'))"))
54
+ java: |
55
+ (method_invocation
56
+ name: (identifier) @method
57
+ (#match? @method "^(setSecure|setHttpOnly)$")
58
+ arguments: (argument_list
59
+ (false))) @match
60
+
61
+ (method_invocation
62
+ name: (identifier) @method
63
+ (#eq? @method "addCookie")
64
+ arguments: (argument_list
65
+ (object_creation_expression
66
+ type: (type_identifier) @t
67
+ (#eq? @t "Cookie")))) @match
68
+
69
+ ruby: |
70
+ ((assignment
71
+ left: (element_reference
72
+ object: (identifier) @obj (#eq? @obj "cookies")
73
+ [(_)])
74
+ right: (_)) @match
75
+ (#not-match? @match "(secure|httponly|same_site)"))
76
+
77
+ message-captures: [match]
@@ -0,0 +1,130 @@
1
+ rule-id: configuration.missing-ssl-verification
2
+
3
+ cases:
4
+ - name: triggers on rejectUnauthorized false in javascript
5
+ language: javascript
6
+ code: |
7
+ const https = require('https');
8
+ https.createServer({ rejectUnauthorized: false }, app);
9
+ expect:
10
+ count: 1
11
+ severity: high
12
+
13
+ - name: triggers on rejectUnauthorized false in typescript
14
+ language: typescript
15
+ code: |
16
+ import https from 'https';
17
+ https.createServer({ rejectUnauthorized: false }, app);
18
+ expect:
19
+ count: 1
20
+ severity: high
21
+
22
+ - name: triggers on rejectUnauthorized false in tsx
23
+ language: tsx
24
+ code: |
25
+ import https from 'https';
26
+ https.createServer({ rejectUnauthorized: false }, app);
27
+ expect:
28
+ count: 1
29
+ severity: high
30
+
31
+ - name: ignores safe value
32
+ language: javascript
33
+ code: |
34
+ https.createServer({ rejectUnauthorized: true }, app);
35
+ expect:
36
+ count: 0
37
+
38
+ - name: ignores safe value in typescript
39
+ language: typescript
40
+ code: |
41
+ import https from 'https';
42
+ https.createServer({ rejectUnauthorized: true }, app);
43
+ expect:
44
+ count: 0
45
+
46
+ - name: triggers on requests.get with verify=False in python
47
+ language: python
48
+ code: |
49
+ requests.get("https://example.com", verify=False)
50
+ expect:
51
+ count: 1
52
+ severity: high
53
+ - name: triggers on httpx.post with verify=False in python
54
+ language: python
55
+ code: |
56
+ httpx.post("https://api.example.com", verify=False)
57
+ expect:
58
+ count: 1
59
+ severity: high
60
+ - name: triggers on curl insecure flag in bash
61
+ language: bash
62
+ code: |
63
+ curl -k https://example.com
64
+ expect:
65
+ count: 1
66
+ severity: high
67
+ - name: ignores requests.get without verify in python
68
+ language: python
69
+ code: |
70
+ requests.get("https://example.com")
71
+ expect:
72
+ count: 0
73
+ - name: ignores requests.get with verify=True in python
74
+ language: python
75
+ code: |
76
+ requests.get("https://example.com", verify=True)
77
+ expect:
78
+ count: 0
79
+ - name: ignores curl without insecure flag in bash
80
+ language: bash
81
+ code: |
82
+ curl https://example.com
83
+ expect:
84
+ count: 0
85
+
86
+ - name: triggers on danger_accept_invalid_certs in rust
87
+ language: rust
88
+ code: |
89
+ client.danger_accept_invalid_certs(true)
90
+ expect:
91
+ count: 1
92
+ severity: high
93
+
94
+ - name: ignores safe client in rust
95
+ language: rust
96
+ code: |
97
+ client.get("https://example.com")
98
+ expect:
99
+ count: 0
100
+
101
+ - name: triggers on setDefaultHostnameVerifier in java
102
+ language: java
103
+ code: |
104
+ HttpsURLConnection.setDefaultHostnameVerifier((host, session) -> true);
105
+ expect:
106
+ count: 1
107
+ severity: high
108
+
109
+ - name: ignores unrelated java code
110
+ language: java
111
+ code: |
112
+ System.out.println("ok");
113
+ expect:
114
+ count: 0
115
+
116
+ - name: ignores safe hostname verifier in java
117
+ language: java
118
+ code: |
119
+ HttpsURLConnection.setDefaultHostnameVerifier((host, session) -> host.equals("secure.com"));
120
+ expect:
121
+ count: 0
122
+
123
+ - name: triggers on VERIFY_NONE in ruby
124
+ language: ruby
125
+ code: |
126
+ http = Net::HTTP.new("example.com", 443)
127
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
128
+ expect:
129
+ count: 1
130
+ severity: high
@@ -0,0 +1,123 @@
1
+ # source: clean-room
2
+ # licence: MIT
3
+ # vendored-at: 2026-05-20
4
+ # verified-by: Seaworthy team
5
+ # attribution: CWE-295
6
+ id: configuration.missing-ssl-verification
7
+ severity: high
8
+ category: configuration
9
+ min-tier: pro
10
+ languages: [javascript, typescript, tsx, python, bash, rust, java, ruby]
11
+
12
+ copy:
13
+ name-key: checks.missing-ssl-verification.name
14
+ description-key: checks.missing-ssl-verification.description
15
+ message-key: checks.missing-ssl-verification.message
16
+ degraded-key: checks.missing-ssl-verification.degraded
17
+ remediation-key: remediation.configuration.missing-ssl-verification
18
+
19
+ confidence: high
20
+
21
+ queries:
22
+ javascript: |
23
+ (call_expression
24
+ function: (member_expression
25
+ object: (identifier) @obj
26
+ property: (property_identifier) @prop)
27
+ arguments: (arguments
28
+ (object
29
+ (pair
30
+ key: (property_identifier) @key
31
+ value: (false) @val)))
32
+ (#eq? @prop "createServer")
33
+ (#eq? @key "rejectUnauthorized")) @match
34
+ typescript: |
35
+ (call_expression
36
+ function: (member_expression
37
+ object: (identifier) @obj
38
+ property: (property_identifier) @prop)
39
+ arguments: (arguments
40
+ (object
41
+ (pair
42
+ key: (property_identifier) @key
43
+ value: (false) @val)))
44
+ (#eq? @prop "createServer")
45
+ (#eq? @key "rejectUnauthorized")) @match
46
+ tsx: |
47
+ (call_expression
48
+ function: (member_expression
49
+ object: (identifier) @obj
50
+ property: (property_identifier) @prop)
51
+ arguments: (arguments
52
+ (object
53
+ (pair
54
+ key: (property_identifier) @key
55
+ value: (false) @val)))
56
+ (#eq? @prop "createServer")
57
+ (#eq? @key "rejectUnauthorized")) @match
58
+ python: |
59
+ (call
60
+ function: (attribute
61
+ object: (identifier) @obj
62
+ attribute: (identifier) @method)
63
+ arguments: (argument_list
64
+ (keyword_argument
65
+ name: (identifier) @key
66
+ value: (false) @val))
67
+ (#match? @obj "^(requests|httpx)$")
68
+ (#match? @method "^(get|post|put|patch|delete|head|options)$")
69
+ (#eq? @key "verify")) @match
70
+ bash: |
71
+ (command
72
+ name: (command_name (word) @cmd)
73
+ argument: (word) @flag
74
+ (#match? @cmd "^(curl|wget)$")
75
+ (#match? @flag "^(-k|--insecure|--no-check-certificate)$")) @match
76
+ rust: |
77
+ (call_expression
78
+ function: (field_expression
79
+ field: (field_identifier) @func
80
+ (#eq? @func "danger_accept_invalid_certs"))) @match
81
+
82
+ java: |
83
+ (method_invocation
84
+ name: (identifier) @method
85
+ (#match? @method "^(setDefaultHostnameVerifier|setHostnameVerifier|setSSLHostnameVerifier)$")
86
+ arguments: (argument_list
87
+ (field_access
88
+ object: (identifier) @obj
89
+ field: (identifier) @field
90
+ (#eq? @obj "NoopHostnameVerifier")
91
+ (#eq? @field "INSTANCE")))) @match
92
+
93
+ (method_invocation
94
+ name: (identifier) @method
95
+ (#match? @method "^(setDefaultHostnameVerifier|setHostnameVerifier|setSSLHostnameVerifier)$")
96
+ arguments: (argument_list
97
+ (identifier) @id
98
+ (#eq? @id "ALLOW_ALL_HOSTNAME_VERIFIER"))) @match
99
+
100
+ (method_invocation
101
+ name: (identifier) @method
102
+ (#match? @method "^(setDefaultHostnameVerifier|setHostnameVerifier|setSSLHostnameVerifier)$")
103
+ arguments: (argument_list
104
+ (lambda_expression
105
+ (true)))) @match
106
+
107
+ (method_invocation
108
+ name: (identifier) @method
109
+ (#match? @method "^(setDefaultHostnameVerifier|setHostnameVerifier|setSSLHostnameVerifier)$")
110
+ arguments: (argument_list
111
+ (lambda_expression
112
+ (block
113
+ (return_statement
114
+ (true)))))) @match
115
+
116
+ ruby: |
117
+ (scope_resolution
118
+ scope: (scope_resolution
119
+ scope: (constant) @o (#eq? @o "OpenSSL")
120
+ name: (constant) @s (#eq? @s "SSL"))
121
+ name: (constant) @v (#eq? @v "VERIFY_NONE")) @match
122
+
123
+ message-captures: [match]
@@ -0,0 +1,143 @@
1
+ rule-id: data-exposure.debug-artifacts
2
+
3
+ cases:
4
+ - name: triggers on debugger statement in javascript
5
+ language: javascript
6
+ code: |
7
+ debugger;
8
+ expect:
9
+ count: 1
10
+ severity: low
11
+
12
+ - name: triggers on debugger in typescript
13
+ language: typescript
14
+ code: |
15
+ function foo() {
16
+ debugger;
17
+ }
18
+ expect:
19
+ count: 1
20
+ severity: low
21
+
22
+ - name: triggers on debugger in tsx
23
+ language: tsx
24
+ code: |
25
+ debugger;
26
+ expect:
27
+ count: 1
28
+ severity: low
29
+
30
+ - name: triggers on pdb import in python
31
+ language: python
32
+ code: |
33
+ from pdb import set_trace
34
+ expect:
35
+ count: 1
36
+ severity: low
37
+
38
+ - name: triggers on xtrace in bash
39
+ language: bash
40
+ code: |
41
+ set -x
42
+ expect:
43
+ count: 1
44
+ severity: low
45
+
46
+ - name: ignores normal code
47
+ language: javascript
48
+ code: |
49
+ console.log("ok")
50
+ expect:
51
+ count: 0
52
+
53
+ - name: ignores normal code in typescript
54
+ language: typescript
55
+ code: |
56
+ console.log("ok")
57
+ expect:
58
+ count: 0
59
+
60
+ - name: ignores normal python code
61
+ language: python
62
+ code: |
63
+ import json
64
+ expect:
65
+ count: 0
66
+
67
+ - name: triggers on binding.pry in ruby
68
+ language: ruby
69
+ code: |
70
+ binding.pry
71
+ expect:
72
+ count: 1
73
+ severity: low
74
+
75
+ - name: ignores errexit in bash
76
+ language: bash
77
+ code: |
78
+ set -e
79
+ expect:
80
+ count: 0
81
+
82
+ - name: triggers on dbg macro in rust
83
+ language: rust
84
+ code: |
85
+ dbg!(x)
86
+ expect:
87
+ count: 1
88
+ severity: low
89
+
90
+ - name: ignores println macro in rust
91
+ language: rust
92
+ code: |
93
+ println!("ok")
94
+ expect:
95
+ count: 0
96
+
97
+ - name: triggers on debug comment in html
98
+ language: html
99
+ code: |
100
+ <!-- DEBUG: fix this -->
101
+ expect:
102
+ count: 1
103
+ severity: low
104
+
105
+ - name: triggers on todo comment in css
106
+ language: css
107
+ code: |
108
+ /* TODO: fix this */
109
+ expect:
110
+ count: 1
111
+ severity: low
112
+
113
+ - name: ignores normal html comment
114
+ language: html
115
+ code: |
116
+ <!-- normal comment -->
117
+ expect:
118
+ count: 0
119
+
120
+ - name: ignores normal css comment
121
+ language: css
122
+ code: |
123
+ /* normal comment */
124
+ expect:
125
+ count: 0
126
+
127
+ - name: triggers on TODO line comment in java
128
+ language: java
129
+ code: |
130
+ // TODO: remove before release
131
+ class App {}
132
+ expect:
133
+ count: 1
134
+ severity: low
135
+
136
+ - name: ignores java source without debug markers
137
+ language: java
138
+ code: |
139
+ class App {
140
+ int x = 1;
141
+ }
142
+ expect:
143
+ count: 0
@@ -0,0 +1,57 @@
1
+ # source: clean-room
2
+ # licence: MIT
3
+ # vendored-at: 2026-05-20
4
+ # verified-by: Seaworthy team
5
+ # attribution: CWE-489
6
+ id: data-exposure.debug-artifacts
7
+ severity: low
8
+ category: data-exposure
9
+ min-tier: pro
10
+ languages: [javascript, typescript, tsx, python, bash, rust, java, ruby, html, css]
11
+
12
+ copy:
13
+ name-key: checks.debug-artifacts.name
14
+ description-key: checks.debug-artifacts.description
15
+ message-key: checks.debug-artifacts.message
16
+ degraded-key: checks.debug-artifacts.degraded
17
+ remediation-key: remediation.data-exposure.debug-artifacts
18
+
19
+ confidence: medium
20
+
21
+ queries:
22
+ javascript: |
23
+ (debugger_statement) @match
24
+ typescript: |
25
+ (debugger_statement) @match
26
+ tsx: |
27
+ (debugger_statement) @match
28
+ python: |
29
+ (import_from_statement
30
+ module_name: (dotted_name) @mod
31
+ name: (dotted_name) @name
32
+ (#eq? @mod "pdb")) @match
33
+ bash: |
34
+ (command
35
+ name: (command_name (word) @cmd)
36
+ argument: (word) @arg
37
+ (#eq? @cmd "set")
38
+ (#match? @arg "^-(x|o\\s+xtrace)$")) @match
39
+ rust: |
40
+ (macro_invocation
41
+ macro: (identifier) @name
42
+ (#eq? @name "dbg")) @match
43
+ java: |
44
+ (line_comment) @match
45
+ (#match? @match "(TODO|FIXME|HACK|DEBUG)")
46
+ html: |
47
+ (comment) @match
48
+ (#match? @match "DEBUG|TODO|HACK|FIXME")
49
+ css: |
50
+ (comment) @match
51
+ (#match? @match "DEBUG|TODO|HACK|FIXME")
52
+ ruby: |
53
+ (call
54
+ method: (identifier) @method
55
+ (#match? @method "^(pry|debugger|byebug)$")) @match
56
+
57
+ message-captures: [match]