@archpublicwebsite/eslint-config 1.0.16 → 1.0.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archpublicwebsite/eslint-config",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "author": "Archipelago Hotels",
5
5
  "description": "Reusable ESLint flat config and git-hook toolkit for Archipelago projects",
6
6
  "type": "module",
@@ -62,18 +62,6 @@ export const FILE_PATTERNS = [
62
62
  message: 'String.fromCharCode sequence — common technique to obfuscate malicious strings',
63
63
  regex: /String\.fromCharCode\s*\(\s*(?:\d+\s*,\s*){4,}\d+\s*\)/,
64
64
  },
65
- {
66
- id: 'unicode-bidi-control',
67
- severity: 'critical',
68
- message: 'Unicode bidi control characters detected — hidden code/trick rendering attack (Trojan Source)',
69
- regex: /[\u202A-\u202E\u2066-\u2069]/,
70
- },
71
- {
72
- id: 'zero-width-hidden-char',
73
- severity: 'high',
74
- message: 'Zero-width/invisible Unicode characters detected — possible hidden payload marker',
75
- regex: /[\u200B-\u200D\uFEFF]/,
76
- },
77
65
  {
78
66
  id: 'hex-string-obfuscation',
79
67
  severity: 'high',
@@ -91,17 +79,10 @@ export const FILE_PATTERNS = [
91
79
  configOnly: true,
92
80
  },
93
81
  {
94
- id: 'http-in-config-require',
82
+ id: 'http-in-config',
95
83
  severity: 'critical',
96
84
  message: 'HTTP/HTTPS module in build config — potential data-exfiltration vector',
97
- regex: /require\s*\(\s*['"](?:node:)?https?['"]\s*\)/,
98
- configOnly: true,
99
- },
100
- {
101
- id: 'http-in-config-import',
102
- severity: 'critical',
103
- message: 'HTTP/HTTPS module in build config — potential data-exfiltration vector',
104
- regex: /from\s+['"](?:node:)?https?['"]/,
85
+ regex: /require\s*\(\s*['"](?:node:)?https?['"]\s*\)|from\s+['"](?:node:)?https?['"]/,
105
86
  configOnly: true,
106
87
  },
107
88
  {
@@ -183,26 +164,16 @@ export const FILE_PATTERNS = [
183
164
  id: 'function-constructor-via-array',
184
165
  severity: 'critical',
185
166
  message: 'Function constructor accessed via decoded array — used to run hidden payload without calling new Function() directly',
186
- // Generalised: identifier assigned from decoded array accessor, then invoked.
187
- regex: /=\s*\w+\s*\[\s*\w+\s*\]\s*;.{0,80}\w+\s*\(\s*\w+\s*,\s*\w+\s*\(\s*\w+\s*\)\s*\)/,
167
+ // Matches: var x = sfL[EKc] where the array was built from a string decoder
168
+ // Generalised: identifier assigned from identifier[short-identifier] then called as a function
169
+ regex: /=\s*\w{2,5}\s*\[\s*\w{2,5}\s*\]\s*;[^;]{0,60}=\s*\w{2,5}\s*\(\s*\w+\s*,\s*\w{2,5}\s*\(\s*\w+\s*\)\s*\)/,
188
170
  },
189
171
  {
190
- id: 'global-bracket-assignment-index',
172
+ id: 'global-bracket-assignment',
191
173
  severity: 'high',
192
174
  message: 'global[variable] assignment — indirect global mutation used to smuggle require/module references',
193
- regex: /global\s*\[\s*[\w$]+\s*\[\s*\d+\s*\]\s*\]\s*=/,
194
- },
195
- {
196
- id: 'global-bracket-assignment-string',
197
- severity: 'high',
198
- message: 'global[variable] assignment — indirect global mutation used to smuggle require/module references',
199
- regex: /global\s*\[\s*['"][^'"]{1,40}['"]\s*\]\s*=/,
200
- },
201
- {
202
- id: 'global-bracket-assignment-var',
203
- severity: 'high',
204
- message: 'global[variable] assignment — indirect global mutation used to smuggle require/module references',
205
- regex: /global\s*\[\s*[\w$]+\s*\]\s*=/,
175
+ // Matches: global[anyVar[index]] = ... OR global['key'] = ... OR global[variable] = ...
176
+ regex: /global\s*\[\s*(?:[\w$]+\s*\[\s*\d+\s*\]|['"][^'"]{1,40}['"]|[\w$]+)\s*\]\s*=/,
206
177
  },
207
178
  {
208
179
  id: 'module-global-hijack',
@@ -210,18 +181,6 @@ export const FILE_PATTERNS = [
210
181
  message: 'global[...] = module — dropper technique to expose Node module reference as a global',
211
182
  regex: /global\s*\[.*?\]\s*=\s*module\b/,
212
183
  },
213
- {
214
- id: 'define-property-backdoor-getter',
215
- severity: 'critical',
216
- message: 'Object.defineProperty used to define hidden getter/setter/value with dynamic execution — potential backdoor',
217
- regex: /Object\.defineProperty\s*\([^)]*\b(?:get|set)\s*:\s*(?:function|\([^)]*\)\s*=>)/,
218
- },
219
- {
220
- id: 'define-property-backdoor-value',
221
- severity: 'critical',
222
- message: 'Object.defineProperty used to define hidden getter/setter/value with dynamic execution — potential backdoor',
223
- regex: /Object\.defineProperty\s*\([^)]*\bvalue\s*:\s*(?:eval\s*\(|new\s+Function\s*\(|require\s*\()/,
224
- },
225
184
  ]
226
185
 
227
186
  // ─── Install-script patterns ───────────────────────────────────────────────────
@@ -25,7 +25,7 @@ const testCases = [
25
25
  },
26
26
  {
27
27
  label: 'Dropper — global bracket assignment via decoded array',
28
- expectedId: 'global-bracket-assignment-index',
28
+ expectedId: 'global-bracket-assignment',
29
29
  line: "global[_$_1e42[2]]= module",
30
30
  },
31
31
  {
@@ -68,22 +68,7 @@ const testCases = [
68
68
  {
69
69
  label: 'Hex-escaped string payload',
70
70
  expectedId: 'hex-string-obfuscation',
71
- line: String.raw`const k='\x68\x65\x6c\x6c\x6f\x77\x6f\x72\x6c\x64\x68\x65\x6c\x6c\x6f\x77\x6f\x72\x6c\x64\x20\x68'`,
72
- },
73
- {
74
- label: 'Trojan Source (unicode bidi control)',
75
- expectedId: 'unicode-bidi-control',
76
- line: 'const safe = true;\u202E // hidden direction override',
77
- },
78
- {
79
- label: 'Zero-width hidden character',
80
- expectedId: 'zero-width-hidden-char',
81
- line: 'const key = "api\u200BToken"',
82
- },
83
- {
84
- label: 'defineProperty hidden getter backdoor',
85
- expectedId: 'define-property-backdoor-getter',
86
- line: 'Object.defineProperty(globalThis, "loader", { get: function(){ return eval(secret) } })',
71
+ line: `const k='\\x68\\x65\\x6c\\x6c\\x6f\\x77\\x6f\\x72\\x6c\\x64\\x68\\x65\\x6c\\x6c\\x6f\\x77\\x6f\\x72\\x6c\\x64\\x20\\x68'`,
87
72
  },
88
73
  {
89
74
  label: 'Prototype pollution',
@@ -125,6 +110,5 @@ for (const tc of testCases) {
125
110
  }
126
111
 
127
112
  console.log(`\n${'─'.repeat(50)}`)
128
- const failedText = failed > 0 ? `${RED}${BOLD}${failed} FAILED${R}` : ''
129
- console.log(`${passed} passed ${failedText}`)
113
+ console.log(`${passed} passed ${failed > 0 ? `${RED}${BOLD}${failed} FAILED${R}` : ''}`)
130
114
  if (failed > 0) process.exit(1)