@q32/signal-scanner 0.1.0 → 0.2.0

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 (100) hide show
  1. package/COPYING +674 -0
  2. package/COPYING.LESSER +165 -0
  3. package/README.md +57 -9
  4. package/dist/cli.d.ts +26 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +592 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/dynamic.d.ts +43 -0
  9. package/dist/dynamic.d.ts.map +1 -0
  10. package/{src/dynamic.ts → dist/dynamic.js} +133 -156
  11. package/dist/dynamic.js.map +1 -0
  12. package/dist/feeds.d.ts +66 -0
  13. package/dist/feeds.d.ts.map +1 -0
  14. package/dist/feeds.js +259 -0
  15. package/dist/feeds.js.map +1 -0
  16. package/dist/index.d.ts +110 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +1251 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/intel.d.ts +72 -0
  21. package/dist/intel.d.ts.map +1 -0
  22. package/dist/intel.js +480 -0
  23. package/dist/intel.js.map +1 -0
  24. package/dist/node-tls.d.ts +8 -0
  25. package/dist/node-tls.d.ts.map +1 -0
  26. package/dist/node-tls.js +48 -0
  27. package/dist/node-tls.js.map +1 -0
  28. package/dist/render-isolate/entry.d.ts +2 -0
  29. package/dist/render-isolate/entry.d.ts.map +1 -0
  30. package/dist/render-isolate/entry.js +3 -0
  31. package/dist/render-isolate/entry.js.map +1 -0
  32. package/dist/render-isolate/polyfills.d.ts +2 -0
  33. package/dist/render-isolate/polyfills.d.ts.map +1 -0
  34. package/dist/render-isolate/polyfills.js +41 -0
  35. package/dist/render-isolate/polyfills.js.map +1 -0
  36. package/dist/render-isolate/run.d.ts +3 -0
  37. package/dist/render-isolate/run.d.ts.map +1 -0
  38. package/dist/render-isolate/run.js +88 -0
  39. package/dist/render-isolate/run.js.map +1 -0
  40. package/dist/render.d.ts +26 -0
  41. package/dist/render.d.ts.map +1 -0
  42. package/dist/render.js +248 -0
  43. package/dist/render.js.map +1 -0
  44. package/dist/rules/packs/binary.d.ts +4 -0
  45. package/dist/rules/packs/binary.d.ts.map +1 -0
  46. package/dist/rules/packs/binary.js +101 -0
  47. package/dist/rules/packs/binary.js.map +1 -0
  48. package/dist/rules/packs/css.d.ts +3 -0
  49. package/dist/rules/packs/css.d.ts.map +1 -0
  50. package/dist/rules/packs/css.js +43 -0
  51. package/dist/rules/packs/css.js.map +1 -0
  52. package/dist/rules/packs/decoders.d.ts +3 -0
  53. package/dist/rules/packs/decoders.d.ts.map +1 -0
  54. package/dist/rules/packs/decoders.js +46 -0
  55. package/dist/rules/packs/decoders.js.map +1 -0
  56. package/dist/rules/packs/html.d.ts +4 -0
  57. package/dist/rules/packs/html.d.ts.map +1 -0
  58. package/dist/rules/packs/html.js +227 -0
  59. package/dist/rules/packs/html.js.map +1 -0
  60. package/dist/rules/packs/index.d.ts +24 -0
  61. package/dist/rules/packs/index.d.ts.map +1 -0
  62. package/dist/rules/packs/index.js +75 -0
  63. package/dist/rules/packs/index.js.map +1 -0
  64. package/dist/rules/packs/script-risk.d.ts +4 -0
  65. package/dist/rules/packs/script-risk.d.ts.map +1 -0
  66. package/dist/rules/packs/script-risk.js +231 -0
  67. package/dist/rules/packs/script-risk.js.map +1 -0
  68. package/dist/rules/packs/source-code.d.ts +3 -0
  69. package/dist/rules/packs/source-code.d.ts.map +1 -0
  70. package/dist/rules/packs/source-code.js +179 -0
  71. package/dist/rules/packs/source-code.js.map +1 -0
  72. package/dist/rules/packs/urls.d.ts +3 -0
  73. package/dist/rules/packs/urls.d.ts.map +1 -0
  74. package/dist/rules/packs/urls.js +123 -0
  75. package/dist/rules/packs/urls.js.map +1 -0
  76. package/dist/rules/types.d.ts +34 -0
  77. package/dist/rules/types.d.ts.map +1 -0
  78. package/dist/rules/types.js +2 -0
  79. package/dist/rules/types.js.map +1 -0
  80. package/package.json +33 -18
  81. package/scripts/check-coverage.ts +0 -33
  82. package/scripts/eval.ts +0 -311
  83. package/scripts/render-isolate/entry.ts +0 -2
  84. package/scripts/render-isolate/polyfills.ts +0 -33
  85. package/scripts/render-isolate/run.ts +0 -63
  86. package/scripts/scan.ts +0 -612
  87. package/src/feeds.ts +0 -334
  88. package/src/index.ts +0 -1366
  89. package/src/intel.ts +0 -561
  90. package/src/node-tls.ts +0 -55
  91. package/src/render.ts +0 -233
  92. package/src/rules/packs/binary.ts +0 -103
  93. package/src/rules/packs/css.ts +0 -44
  94. package/src/rules/packs/decoders.ts +0 -47
  95. package/src/rules/packs/html.ts +0 -255
  96. package/src/rules/packs/index.ts +0 -76
  97. package/src/rules/packs/script-risk.ts +0 -236
  98. package/src/rules/packs/source-code.ts +0 -180
  99. package/src/rules/packs/urls.ts +0 -138
  100. package/src/rules/types.ts +0 -56
@@ -1,76 +0,0 @@
1
- export { binaryRules, binaryStringRules } from "./binary";
2
- export { cssRules } from "./css";
3
- export { decodedArtifactRules } from "./decoders";
4
- export { htmlRules } from "./html";
5
- export { htmlTechnologyRules } from "./html";
6
- export { scriptCompositeRules, scriptRiskRules } from "./script-risk";
7
- export { sourceCodeRules } from "./source-code";
8
- export { urlRules } from "./urls";
9
-
10
- import { binaryRules, binaryStringRules } from "./binary";
11
- import { cssRules } from "./css";
12
- import { decodedArtifactRules } from "./decoders";
13
- import { htmlRules, htmlTechnologyRules } from "./html";
14
- import { scriptCompositeRules, scriptRiskRules } from "./script-risk";
15
- import { sourceCodeRules } from "./source-code";
16
- import { urlRules } from "./urls";
17
-
18
- export const rulePacks = {
19
- phishing: [
20
- htmlRules.credential_form_posts_off_origin,
21
- htmlRules.password_form_without_https,
22
- htmlRules.hidden_iframe_off_origin,
23
- htmlRules.excessive_external_scripts_on_login_page,
24
- htmlRules.login_page_with_punycode_links,
25
- htmlRules.credential_ui_rendered_as_image,
26
- htmlRules.crypto_wallet_login_language,
27
- htmlRules.crypto_trading_landing_language,
28
- htmlRules.seo_trademark_stuffing,
29
- htmlRules.credential_form_on_suspicious_host,
30
- htmlRules.brand_impersonation_content,
31
- urlRules.punycode_login_url,
32
- urlRules.brand_impersonation_url
33
- ],
34
- redirects: [htmlRules.meta_refresh_external, urlRules.redirect_to_url_shortener, urlRules.final_url_offsite_redirect, ...scriptRiskRules.filter((rule) => rule.pack === "redirects")],
35
- "url-risk": [
36
- urlRules.private_ip_url,
37
- urlRules.ip_literal_url,
38
- urlRules.suspicious_tld_url,
39
- urlRules.download_like_external_url,
40
- urlRules.malware_download_like_url,
41
- urlRules.shared_hosting_subdomain_url,
42
- urlRules.brand_impersonation_url,
43
- urlRules.generated_landing_url
44
- ],
45
- "technology-fingerprint": [
46
- htmlTechnologyRules.wordpress_surface_reference,
47
- htmlTechnologyRules.drupal_surface_reference,
48
- htmlTechnologyRules.phpmyadmin_surface_reference
49
- ],
50
- "dependency-fingerprint": [
51
- htmlTechnologyRules.legacy_jquery_reference,
52
- htmlTechnologyRules.legacy_angularjs_reference,
53
- htmlTechnologyRules.legacy_bootstrap_reference,
54
- htmlTechnologyRules.legacy_lodash_reference
55
- ],
56
- "script-risk": [
57
- htmlRules.external_script_from_unrelated_domain,
58
- htmlRules.mixed_content_script,
59
- ...scriptRiskRules.filter((rule) => rule.pack === "script-risk")
60
- ],
61
- obfuscation: [
62
- ...Object.values(decodedArtifactRules),
63
- ...scriptRiskRules.filter((rule) => rule.pack === "obfuscation"),
64
- scriptCompositeRules.decoded_dynamic_execution,
65
- cssRules.unicode_bidi_trick
66
- ],
67
- exfiltration: [
68
- ...scriptRiskRules.filter((rule) => rule.pack === "exfiltration"),
69
- scriptCompositeRules.credential_exfil_candidate
70
- ],
71
- wallet: scriptRiskRules.filter((rule) => rule.pack === "wallet"),
72
- payment: [htmlRules.card_fields_plus_external_script, scriptCompositeRules.payment_input_event_hooks],
73
- "seo-spam": [cssRules.hidden_link_cluster],
74
- "source-code": sourceCodeRules,
75
- "binary-static": [...Object.values(binaryRules), ...binaryStringRules]
76
- } as const;
@@ -1,236 +0,0 @@
1
- import type { PatternRule, RuleDefinition } from "../types";
2
-
3
- export const scriptRiskRules: PatternRule[] = [
4
- {
5
- id: "dynamic_code_execution",
6
- pack: "script-risk",
7
- severity: "low",
8
- confidence: "medium",
9
- title: "Dynamic code execution",
10
- description: "JavaScript calls eval().",
11
- locationType: "javascript",
12
- pattern: /\beval\s*\(/,
13
- counter: "dynamic_code_execution",
14
- // eval() is ubiquitous in legitimate minified bundles; weak signal alone.
15
- score: { base: 12, tags: ["script"], maxGroup: "dynamic-code" }
16
- },
17
- {
18
- id: "function_constructor_with_string",
19
- pack: "script-risk",
20
- severity: "low",
21
- confidence: "medium",
22
- title: "Function constructor with string",
23
- description: "JavaScript constructs code from a string.",
24
- locationType: "javascript",
25
- pattern: /\bnew\s+Function\s*\(/,
26
- // new Function() is ubiquitous in legitimate minified bundles (framework
27
- // template compilers, lodash, etc.) — weak signal alone, like eval().
28
- score: { base: 15, tags: ["script"], maxGroup: "dynamic-code" }
29
- },
30
- {
31
- id: "string_timer_execution",
32
- pack: "script-risk",
33
- severity: "medium",
34
- confidence: "high",
35
- title: "String-based timer execution",
36
- description: "JavaScript passes a string to a timer execution API.",
37
- locationType: "javascript",
38
- pattern: /\bset(?:Timeout|Interval)\s*\(\s*['"`]/,
39
- counter: "dynamic_code_execution",
40
- score: { base: 24, tags: ["script"], maxGroup: "dynamic-code" }
41
- },
42
- {
43
- id: "document_write_script",
44
- pack: "script-risk",
45
- severity: "low",
46
- confidence: "high",
47
- title: "document.write usage",
48
- description: "JavaScript writes dynamic HTML into the document.",
49
- locationType: "javascript",
50
- pattern: /\bdocument\.write\s*\(/,
51
- score: { base: 8, tags: ["script"] }
52
- },
53
- {
54
- id: "innerhtml_script_injection",
55
- pack: "script-risk",
56
- severity: "low",
57
- confidence: "high",
58
- title: "HTML injection sink",
59
- description: "JavaScript assigns to an HTML injection sink.",
60
- locationType: "javascript",
61
- pattern: /\.(?:innerHTML|outerHTML)\s*=/,
62
- score: { base: 10, tags: ["script"] }
63
- },
64
- {
65
- id: "insert_adjacent_html",
66
- pack: "script-risk",
67
- severity: "low",
68
- confidence: "high",
69
- title: "insertAdjacentHTML usage",
70
- description: "JavaScript inserts HTML through insertAdjacentHTML().",
71
- locationType: "javascript",
72
- pattern: /\.insertAdjacentHTML\s*\(/,
73
- score: { base: 8, tags: ["script"] }
74
- },
75
- {
76
- id: "dynamic_script_src",
77
- pack: "script-risk",
78
- severity: "medium",
79
- confidence: "high",
80
- title: "Dynamic script creation",
81
- description: "JavaScript creates a script element dynamically.",
82
- locationType: "javascript",
83
- pattern: /\bcreateElement\s*\(\s*['"]script['"]\s*\)/,
84
- score: { base: 18, tags: ["script"] }
85
- },
86
- {
87
- id: "script_src_assignment",
88
- pack: "script-risk",
89
- severity: "medium",
90
- confidence: "high",
91
- title: "Dynamic script src assignment",
92
- description: "JavaScript assigns to a script source dynamically.",
93
- locationType: "javascript",
94
- pattern: /\.src\s*=|setAttribute\s*\(\s*['"]src['"]/,
95
- score: { base: 18, tags: ["script"] }
96
- },
97
- {
98
- id: "append_child_script",
99
- pack: "script-risk",
100
- severity: "low",
101
- confidence: "medium",
102
- title: "Dynamic script append",
103
- description: "JavaScript appends a dynamically created script element.",
104
- locationType: "javascript",
105
- pattern: /\.appendChild\s*\(\s*(?:script|s|el|node)\s*\)/,
106
- score: { base: 6, tags: ["script"] }
107
- },
108
- {
109
- id: "external_request_api_seen",
110
- pack: "script-risk",
111
- severity: "low",
112
- confidence: "medium",
113
- title: "External request API",
114
- description: "JavaScript references an outbound request API.",
115
- locationType: "javascript",
116
- pattern: /\b(?:fetch|XMLHttpRequest|sendBeacon|WebSocket)\b/,
117
- score: { base: 6, tags: ["script"] }
118
- },
119
- {
120
- id: "js_location_external",
121
- pack: "redirects",
122
- severity: "medium",
123
- confidence: "high",
124
- title: "JavaScript redirect logic",
125
- description: "JavaScript references browser redirect APIs.",
126
- locationType: "javascript",
127
- pattern: /\b(?:location\.href|location\.assign|location\.replace|window\.open)\b/,
128
- score: { base: 20, tags: ["redirect", "script"] }
129
- },
130
- {
131
- id: "decoder_seen",
132
- pack: "obfuscation",
133
- severity: "low",
134
- confidence: "medium",
135
- title: "Decoder API seen",
136
- description: "JavaScript references a common string decoder API.",
137
- locationType: "javascript",
138
- pattern: /\b(?:atob|btoa|unescape|String\.fromCharCode)\b/,
139
- counter: "decoder_seen",
140
- score: { base: 6, tags: ["decoded", "script"] }
141
- },
142
- {
143
- id: "charcodeat_decoder_loop",
144
- pack: "obfuscation",
145
- severity: "medium",
146
- confidence: "medium",
147
- title: "charCodeAt decoder loop",
148
- description: "JavaScript uses charCodeAt in loop-like code, a common lightweight decoder pattern.",
149
- locationType: "javascript",
150
- pattern: /(?:for|while)\s*\([^)]*\)[\s\S]{0,300}\.charCodeAt\s*\(/,
151
- score: { base: 22, tags: ["decoded", "obfuscation", "script"] }
152
- },
153
- {
154
- id: "browser_storage_or_clipboard_seen",
155
- pack: "exfiltration",
156
- severity: "medium",
157
- confidence: "medium",
158
- title: "Storage or clipboard access",
159
- description: "JavaScript references browser storage, cookies, or clipboard APIs.",
160
- locationType: "javascript",
161
- pattern: /\b(?:localStorage|sessionStorage|document\.cookie|navigator\.clipboard)\b/,
162
- score: { base: 14, tags: ["exfiltration", "script"] }
163
- },
164
- {
165
- id: "wallet_interaction_with_obfuscation",
166
- pack: "wallet",
167
- severity: "medium",
168
- confidence: "medium",
169
- title: "Wallet API reference",
170
- description: "JavaScript references wallet or approval APIs.",
171
- locationType: "javascript",
172
- pattern: /\b(?:window\.ethereum|WalletConnect|ethereum\.request)\b|\.(?:approve|permit)\s*\(|\bmethod\s*:\s*['"]eth_/i,
173
- score: { base: 20, tags: ["script", "wallet"] }
174
- }
175
- ];
176
-
177
- export const scriptCompositeRules: Record<
178
- "credential_exfil_candidate" | "decoded_dynamic_execution" | "form_action_changed_by_javascript" | "wallet_api_plus_external_beacon" | "payment_input_event_hooks",
179
- RuleDefinition
180
- > = {
181
- credential_exfil_candidate: {
182
- id: "credential_exfil_candidate",
183
- pack: "exfiltration",
184
- severity: "high",
185
- confidence: "medium",
186
- title: "Credential or storage exfiltration candidate",
187
- description: "JavaScript combines credential/storage signals with outbound request APIs.",
188
- locationType: "javascript",
189
- score: { base: 72, tags: ["credential", "exfiltration", "script"] }
190
- },
191
- decoded_dynamic_execution: {
192
- id: "decoded_dynamic_execution",
193
- pack: "obfuscation",
194
- severity: "high",
195
- confidence: "high",
196
- title: "Decoded dynamic execution",
197
- description: "JavaScript combines decoder APIs with dynamic execution.",
198
- locationType: "javascript",
199
- score: { base: 76, tags: ["decoded", "obfuscation", "script"] }
200
- },
201
- form_action_changed_by_javascript: {
202
- id: "form_action_changed_by_javascript",
203
- pack: "phishing",
204
- severity: "low",
205
- confidence: "medium",
206
- title: "Form action changed by JavaScript",
207
- description: "JavaScript appears to change a form action target.",
208
- locationType: "javascript",
209
- // Legitimate SPAs/SSO flows rewrite form actions; weak on its own, and the
210
- // "credential"/"phishing" tags were escalating the score multiplier.
211
- score: { base: 12, tags: ["script"] }
212
- },
213
- wallet_api_plus_external_beacon: {
214
- id: "wallet_api_plus_external_beacon",
215
- pack: "wallet",
216
- severity: "high",
217
- confidence: "medium",
218
- title: "Wallet API plus external request",
219
- description: "JavaScript combines wallet APIs with outbound request APIs.",
220
- locationType: "javascript",
221
- score: { base: 72, tags: ["exfiltration", "script", "wallet"] }
222
- },
223
- payment_input_event_hooks: {
224
- id: "payment_input_event_hooks",
225
- pack: "payment",
226
- severity: "low",
227
- confidence: "medium",
228
- title: "Payment input event hooks",
229
- description: "JavaScript attaches input/change listeners near payment-card fields.",
230
- locationType: "javascript",
231
- // Every legitimate checkout/login listens to its own input fields — weak
232
- // signal alone. The real skimmer pattern is this PLUS off-site exfil of the
233
- // captured values, which the exfil/credential-form rules score on their own.
234
- score: { base: 15, tags: ["payment", "script"] }
235
- }
236
- };
@@ -1,180 +0,0 @@
1
- import type { PatternRule } from "../types";
2
-
3
- export const sourceCodeRules: PatternRule[] = [
4
- {
5
- id: "hardcoded_secret_candidate",
6
- pack: "source-code",
7
- severity: "high",
8
- confidence: "medium",
9
- title: "Hardcoded secret candidate",
10
- description: "Source text matched a risky secret-like token pattern.",
11
- locationType: "source",
12
- pattern: /(?:AKIA[0-9A-Z]{16}|xox[baprs]-[a-zA-Z0-9-]{20,}|ghp_[a-zA-Z0-9]{20,})/,
13
- score: { base: 62, tags: ["source"] }
14
- },
15
- {
16
- id: "webhook_url_candidate",
17
- pack: "source-code",
18
- severity: "medium",
19
- confidence: "medium",
20
- title: "Webhook URL candidate",
21
- description: "Source text contains a webhook URL candidate.",
22
- locationType: "source",
23
- pattern: /https:\/\/(?:hooks\.slack\.com\/services\/|discord(?:app)?\.com\/api\/webhooks\/|api\.telegram\.org\/bot)[A-Za-z0-9/_:.-]+/,
24
- score: { base: 35, tags: ["source", "url"] }
25
- },
26
- {
27
- id: "dangerous_child_process",
28
- pack: "source-code",
29
- severity: "high",
30
- confidence: "medium",
31
- title: "Dangerous child process use",
32
- description: "Source text references command execution through child_process.",
33
- locationType: "source",
34
- pattern: /\bchild_process\.(?:exec|execSync|spawn|spawnSync|execFile|execFileSync)\b|require\s*\(\s*['"]child_process['"]\s*\)\s*\.\s*(?:exec|execSync|spawn|spawnSync|execFile|execFileSync)\b|import\s*\{[^}]*\b(?:exec|execSync|spawn|spawnSync|execFile|execFileSync)\b[^}]*\}\s*from\s*['"]node:child_process['"]/,
35
- score: { base: 50, tags: ["source"] }
36
- },
37
- {
38
- id: "shell_execution_import",
39
- pack: "source-code",
40
- severity: "medium",
41
- confidence: "medium",
42
- title: "Shell execution import",
43
- description: "Source text imports Node child_process command execution APIs.",
44
- locationType: "source",
45
- pattern: /\b(?:import|require)\b[^;\n]{0,120}\bchild_process\b/,
46
- score: { base: 24, tags: ["source"] }
47
- },
48
- {
49
- id: "curl_pipe_shell",
50
- pack: "source-code",
51
- severity: "high",
52
- confidence: "medium",
53
- title: "curl pipe shell",
54
- description: "Source text pipes a downloaded script into a shell.",
55
- locationType: "source",
56
- pattern: /\bcurl\b[^|]{0,120}\|\s*(?:sh|bash)/,
57
- score: { base: 70, tags: ["source", "url"] }
58
- },
59
- {
60
- id: "postinstall_script",
61
- pack: "source-code",
62
- severity: "medium",
63
- confidence: "medium",
64
- title: "Postinstall script",
65
- description: "Package metadata defines a postinstall script.",
66
- locationType: "source",
67
- pattern: /"postinstall"\s*:/,
68
- score: { base: 20, tags: ["source"] }
69
- },
70
- {
71
- id: "preinstall_script",
72
- pack: "source-code",
73
- severity: "medium",
74
- confidence: "medium",
75
- title: "Preinstall script",
76
- description: "Package metadata defines a preinstall script.",
77
- locationType: "source",
78
- pattern: /"preinstall"\s*:/,
79
- score: { base: 20, tags: ["source"] }
80
- },
81
- {
82
- id: "install_script_network_fetch",
83
- pack: "source-code",
84
- severity: "high",
85
- confidence: "medium",
86
- title: "Install script performs network fetch",
87
- description: "Install lifecycle script appears to fetch network content.",
88
- locationType: "source",
89
- pattern: /"(?:preinstall|install|postinstall)"\s*:\s*"[^"]*(?:curl|wget|fetch|https?:\/\/)/,
90
- score: { base: 66, tags: ["source", "url"] }
91
- },
92
- {
93
- id: "non_literal_require",
94
- pack: "source-code",
95
- severity: "medium",
96
- confidence: "medium",
97
- title: "Non-literal require candidate",
98
- description: "Source text calls require() with an expression instead of a string literal.",
99
- locationType: "source",
100
- pattern: /\brequire\s*\(\s*(?!['"`])/,
101
- score: { base: 18, tags: ["source"] }
102
- },
103
- {
104
- id: "non_literal_regexp",
105
- pack: "source-code",
106
- severity: "medium",
107
- confidence: "medium",
108
- title: "Non-literal RegExp candidate",
109
- description: "Source text constructs a RegExp from a non-literal expression.",
110
- locationType: "source",
111
- pattern: /\bnew\s+RegExp\s*\(\s*(?!['"`])|\bRegExp\s*\(\s*(?!['"`])/,
112
- score: { base: 16, tags: ["source"] }
113
- },
114
- {
115
- id: "new_buffer_constructor",
116
- pack: "source-code",
117
- severity: "medium",
118
- confidence: "medium",
119
- title: "New Buffer constructor",
120
- description: "Source text uses the legacy Buffer constructor.",
121
- locationType: "source",
122
- pattern: /\bnew\s+Buffer\s*\(/,
123
- score: { base: 12, tags: ["source"] }
124
- },
125
- {
126
- id: "weak_crypto_hash",
127
- pack: "source-code",
128
- severity: "medium",
129
- confidence: "medium",
130
- title: "Weak crypto hash",
131
- description: "Source text references weak hash algorithms.",
132
- locationType: "source",
133
- pattern: /\bcreateHash\s*\(\s*['"](?:md5|sha1)['"]\s*\)/,
134
- score: { base: 16, tags: ["source"] }
135
- },
136
- {
137
- id: "pseudo_random_bytes",
138
- pack: "source-code",
139
- severity: "medium",
140
- confidence: "medium",
141
- title: "Pseudo-random bytes",
142
- description: "Source text references crypto.pseudoRandomBytes().",
143
- locationType: "source",
144
- pattern: /\bpseudoRandomBytes\s*\(/,
145
- score: { base: 16, tags: ["source"] }
146
- },
147
- {
148
- id: "template_escape_disabled",
149
- pack: "source-code",
150
- severity: "medium",
151
- confidence: "medium",
152
- title: "Template escaping disabled",
153
- description: "Source text appears to disable template escaping.",
154
- locationType: "source",
155
- pattern: /\bescapeMarkup\s*=\s*false\b/,
156
- score: { base: 22, tags: ["source"] }
157
- },
158
- {
159
- id: "sensitive_file_read",
160
- pack: "source-code",
161
- severity: "high",
162
- confidence: "medium",
163
- title: "Sensitive file read candidate",
164
- description: "Source text references filesystem reads of sensitive paths or environment files.",
165
- locationType: "source",
166
- pattern: /\b(?:readFileSync|readFile)\s*\([^)]*(?:\/etc\/passwd|\.env|id_rsa|credentials)/,
167
- score: { base: 48, tags: ["source"] }
168
- },
169
- {
170
- id: "private_key_material",
171
- pack: "source-code",
172
- severity: "critical",
173
- confidence: "high",
174
- title: "Private key material",
175
- description: "Source text contains a private key header.",
176
- locationType: "source",
177
- pattern: /-----BEGIN (?:RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----/,
178
- score: { base: 95, tags: ["source"] }
179
- }
180
- ];
@@ -1,138 +0,0 @@
1
- import type { RuleDefinition } from "../types";
2
-
3
- export const urlRules: Record<
4
- | "punycode_login_url"
5
- | "redirect_to_url_shortener"
6
- | "final_url_offsite_redirect"
7
- | "private_ip_url"
8
- | "ip_literal_url"
9
- | "suspicious_tld_url"
10
- | "download_like_external_url"
11
- | "malware_download_like_url"
12
- | "shared_hosting_subdomain_url"
13
- | "brand_impersonation_url"
14
- | "credential_path_on_suspicious_host"
15
- | "generated_landing_url",
16
- RuleDefinition
17
- > = {
18
- punycode_login_url: {
19
- id: "punycode_login_url",
20
- pack: "phishing",
21
- severity: "high",
22
- confidence: "high",
23
- title: "Punycode login URL",
24
- description: "A login-like URL uses punycode.",
25
- locationType: "url",
26
- score: { base: 70, tags: ["phishing", "url"] }
27
- },
28
- redirect_to_url_shortener: {
29
- id: "redirect_to_url_shortener",
30
- pack: "redirects",
31
- severity: "medium",
32
- confidence: "medium",
33
- title: "URL shortener destination",
34
- description: "The scanned URL is, or redirects through, a known URL shortener (a common cloaking step).",
35
- locationType: "url",
36
- score: { base: 20, tags: ["redirect", "url"] }
37
- },
38
- final_url_offsite_redirect: {
39
- id: "final_url_offsite_redirect",
40
- pack: "redirects",
41
- severity: "medium",
42
- confidence: "high",
43
- title: "Final URL redirects off-site",
44
- description: "The fetched URL resolves to a different registrable domain than the submitted URL.",
45
- locationType: "url",
46
- score: { base: 25, tags: ["redirect", "url"] }
47
- },
48
- private_ip_url: {
49
- id: "private_ip_url",
50
- pack: "url-risk",
51
- severity: "medium",
52
- confidence: "high",
53
- title: "Private or local network URL",
54
- description: "Content references a localhost or private-network URL.",
55
- locationType: "url",
56
- score: { base: 25, tags: ["url"] }
57
- },
58
- ip_literal_url: {
59
- id: "ip_literal_url",
60
- pack: "url-risk",
61
- severity: "medium",
62
- confidence: "medium",
63
- title: "IP literal URL",
64
- description: "Content references a URL by IP address instead of a hostname.",
65
- locationType: "url",
66
- score: { base: 22, tags: ["url"] }
67
- },
68
- suspicious_tld_url: {
69
- id: "suspicious_tld_url",
70
- pack: "url-risk",
71
- severity: "low",
72
- confidence: "medium",
73
- title: "Suspicious TLD URL",
74
- description: "Content references a URL with a TLD commonly seen in abuse investigations.",
75
- locationType: "url",
76
- score: { base: 8, tags: ["url"] }
77
- },
78
- download_like_external_url: {
79
- id: "download_like_external_url",
80
- pack: "url-risk",
81
- severity: "medium",
82
- confidence: "medium",
83
- title: "Download-like external URL",
84
- description: "Content references an off-site URL with download or payload path terms.",
85
- locationType: "url",
86
- score: { base: 18, tags: ["url"], repeatMultiplier: 0.25, maxRepeats: 3 }
87
- },
88
- malware_download_like_url: {
89
- id: "malware_download_like_url",
90
- pack: "url-risk",
91
- severity: "high",
92
- confidence: "medium",
93
- title: "Malware-download-like URL path",
94
- description: "URL path resembles common malware download naming for scripts, botnet payloads, or architecture-specific binaries.",
95
- locationType: "url",
96
- score: { base: 55, tags: ["binary", "url"] }
97
- },
98
- shared_hosting_subdomain_url: {
99
- id: "shared_hosting_subdomain_url",
100
- pack: "url-risk",
101
- severity: "low",
102
- confidence: "medium",
103
- title: "Shared-hosting subdomain",
104
- description: "The target URL is hosted on a shared/free-hosting subdomain rather than an independently controlled registrable domain.",
105
- locationType: "url",
106
- score: { base: 6, tags: ["hosting", "url"] }
107
- },
108
- brand_impersonation_url: {
109
- id: "brand_impersonation_url",
110
- pack: "phishing",
111
- severity: "high",
112
- confidence: "high",
113
- title: "Brand name in host of an unrelated domain",
114
- description: "A well-known brand appears in the hostname while the registrable domain does not belong to that brand — a hallmark of credential-phishing lookalike hosts.",
115
- locationType: "url",
116
- score: { base: 68, tags: ["phishing", "url"] }
117
- },
118
- credential_path_on_suspicious_host: {
119
- id: "credential_path_on_suspicious_host",
120
- pack: "phishing",
121
- severity: "high",
122
- confidence: "high",
123
- title: "Login/account path on a suspicious host",
124
- description: "A login, sign-in, account, or verification path is served from a free-hosting subdomain, generated host label, suspicious TLD, punycode, IP literal, or URL shortener — where legitimate brands do not host credentials.",
125
- locationType: "url",
126
- score: { base: 66, tags: ["credential", "phishing", "url"] }
127
- },
128
- generated_landing_url: {
129
- id: "generated_landing_url",
130
- pack: "url-risk",
131
- severity: "high",
132
- confidence: "medium",
133
- title: "Generated suspicious landing URL",
134
- description: "URL has generated-looking host/path structure commonly seen in injected landing pages and fake-update campaigns.",
135
- locationType: "url",
136
- score: { base: 78, tags: ["phishing", "url"] }
137
- }
138
- };
@@ -1,56 +0,0 @@
1
- export type Severity = "info" | "low" | "medium" | "high" | "critical";
2
- export type Confidence = "low" | "medium" | "high";
3
- export type FindingLocationType = "url" | "html" | "javascript" | "css" | "source" | "binary" | "decoded_artifact" | "aggregate";
4
- export type ScoreTag =
5
- | "binary"
6
- | "credential"
7
- | "decoded"
8
- | "dependency"
9
- | "exfiltration"
10
- | "hosting"
11
- | "obfuscation"
12
- | "payment"
13
- | "phishing"
14
- | "redirect"
15
- | "seo"
16
- | "script"
17
- | "source"
18
- | "technology"
19
- | "url"
20
- | "wallet";
21
-
22
- export interface RuleScoreModel {
23
- base: number;
24
- tags: ScoreTag[];
25
- repeatMultiplier?: number;
26
- maxRepeats?: number;
27
- // Rules sharing a maxGroup describe the same underlying behaviour observed
28
- // different ways (e.g. eval / new Function / runtime eval all = "uses dynamic
29
- // code"). Only the single highest-scoring member of a maxGroup contributes to
30
- // the total, so a legit page isn't charged N times for one behaviour.
31
- maxGroup?: string;
32
- }
33
-
34
- export interface PatternRule {
35
- id: string;
36
- pack: string;
37
- severity: Severity;
38
- confidence: Confidence;
39
- title: string;
40
- description: string;
41
- locationType: FindingLocationType;
42
- pattern: RegExp;
43
- counter?: string;
44
- score: RuleScoreModel;
45
- }
46
-
47
- export interface RuleDefinition {
48
- id: string;
49
- pack: string;
50
- severity: Severity;
51
- confidence: Confidence;
52
- title: string;
53
- description: string;
54
- locationType: FindingLocationType;
55
- score: RuleScoreModel;
56
- }