ferret-scan 1.0.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 (69) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/LICENSE +21 -0
  3. package/README.md +416 -0
  4. package/bin/ferret.js +822 -0
  5. package/dist/__tests__/basic.test.d.ts +6 -0
  6. package/dist/__tests__/basic.test.js +80 -0
  7. package/dist/analyzers/AstAnalyzer.d.ts +30 -0
  8. package/dist/analyzers/AstAnalyzer.js +332 -0
  9. package/dist/analyzers/CorrelationAnalyzer.d.ts +21 -0
  10. package/dist/analyzers/CorrelationAnalyzer.js +288 -0
  11. package/dist/index.d.ts +17 -0
  12. package/dist/index.js +22 -0
  13. package/dist/intelligence/IndicatorMatcher.d.ts +50 -0
  14. package/dist/intelligence/IndicatorMatcher.js +285 -0
  15. package/dist/intelligence/ThreatFeed.d.ts +99 -0
  16. package/dist/intelligence/ThreatFeed.js +296 -0
  17. package/dist/remediation/Fixer.d.ts +71 -0
  18. package/dist/remediation/Fixer.js +391 -0
  19. package/dist/remediation/Quarantine.d.ts +102 -0
  20. package/dist/remediation/Quarantine.js +329 -0
  21. package/dist/reporters/ConsoleReporter.d.ts +13 -0
  22. package/dist/reporters/ConsoleReporter.js +185 -0
  23. package/dist/reporters/HtmlReporter.d.ts +25 -0
  24. package/dist/reporters/HtmlReporter.js +604 -0
  25. package/dist/reporters/SarifReporter.d.ts +86 -0
  26. package/dist/reporters/SarifReporter.js +117 -0
  27. package/dist/rules/ai-specific.d.ts +8 -0
  28. package/dist/rules/ai-specific.js +221 -0
  29. package/dist/rules/backdoors.d.ts +8 -0
  30. package/dist/rules/backdoors.js +134 -0
  31. package/dist/rules/correlationRules.d.ts +8 -0
  32. package/dist/rules/correlationRules.js +227 -0
  33. package/dist/rules/credentials.d.ts +8 -0
  34. package/dist/rules/credentials.js +194 -0
  35. package/dist/rules/exfiltration.d.ts +8 -0
  36. package/dist/rules/exfiltration.js +139 -0
  37. package/dist/rules/index.d.ts +51 -0
  38. package/dist/rules/index.js +97 -0
  39. package/dist/rules/injection.d.ts +8 -0
  40. package/dist/rules/injection.js +136 -0
  41. package/dist/rules/obfuscation.d.ts +8 -0
  42. package/dist/rules/obfuscation.js +159 -0
  43. package/dist/rules/permissions.d.ts +8 -0
  44. package/dist/rules/permissions.js +129 -0
  45. package/dist/rules/persistence.d.ts +8 -0
  46. package/dist/rules/persistence.js +117 -0
  47. package/dist/rules/semanticRules.d.ts +10 -0
  48. package/dist/rules/semanticRules.js +212 -0
  49. package/dist/rules/supply-chain.d.ts +8 -0
  50. package/dist/rules/supply-chain.js +148 -0
  51. package/dist/scanner/FileDiscovery.d.ts +24 -0
  52. package/dist/scanner/FileDiscovery.js +282 -0
  53. package/dist/scanner/PatternMatcher.d.ts +25 -0
  54. package/dist/scanner/PatternMatcher.js +206 -0
  55. package/dist/scanner/Scanner.d.ts +14 -0
  56. package/dist/scanner/Scanner.js +266 -0
  57. package/dist/scanner/WatchMode.d.ts +29 -0
  58. package/dist/scanner/WatchMode.js +195 -0
  59. package/dist/types.d.ts +332 -0
  60. package/dist/types.js +53 -0
  61. package/dist/utils/baseline.d.ts +80 -0
  62. package/dist/utils/baseline.js +276 -0
  63. package/dist/utils/config.d.ts +21 -0
  64. package/dist/utils/config.js +247 -0
  65. package/dist/utils/ignore.d.ts +18 -0
  66. package/dist/utils/ignore.js +82 -0
  67. package/dist/utils/logger.d.ts +32 -0
  68. package/dist/utils/logger.js +75 -0
  69. package/package.json +119 -0
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Threat Feed Manager - Manages file-based threat intelligence feeds
3
+ * Provides indicators of compromise (IoCs) for enhanced security detection
4
+ */
5
+ /**
6
+ * Threat intelligence indicator types
7
+ */
8
+ export type IndicatorType = 'domain' | 'url' | 'ip' | 'hash' | 'email' | 'filename' | 'package' | 'pattern' | 'signature';
9
+ /**
10
+ * Threat intelligence source
11
+ */
12
+ export interface ThreatSource {
13
+ name: string;
14
+ url?: string;
15
+ description: string;
16
+ lastUpdated: string;
17
+ enabled: boolean;
18
+ format: 'json' | 'csv' | 'txt';
19
+ }
20
+ /**
21
+ * Threat indicator
22
+ */
23
+ export interface ThreatIndicator {
24
+ value: string;
25
+ type: IndicatorType;
26
+ category: string;
27
+ severity: 'critical' | 'high' | 'medium' | 'low';
28
+ description: string;
29
+ source: string;
30
+ firstSeen: string;
31
+ lastSeen: string;
32
+ confidence: number;
33
+ tags: string[];
34
+ metadata?: Record<string, unknown>;
35
+ }
36
+ /**
37
+ * Threat intelligence database
38
+ */
39
+ export interface ThreatDatabase {
40
+ version: string;
41
+ lastUpdated: string;
42
+ sources: ThreatSource[];
43
+ indicators: ThreatIndicator[];
44
+ stats: {
45
+ totalIndicators: number;
46
+ byType: Record<IndicatorType, number>;
47
+ byCategory: Record<string, number>;
48
+ bySeverity: Record<string, number>;
49
+ };
50
+ }
51
+ /**
52
+ * Load threat intelligence database
53
+ */
54
+ export declare function loadThreatDatabase(intelDir?: string): ThreatDatabase;
55
+ /**
56
+ * Save threat intelligence database
57
+ */
58
+ export declare function saveThreatDatabase(db: ThreatDatabase, intelDir?: string): void;
59
+ /**
60
+ * Add indicators to database
61
+ */
62
+ export declare function addIndicators(db: ThreatDatabase, indicators: Omit<ThreatIndicator, 'firstSeen' | 'lastSeen'>[]): ThreatDatabase;
63
+ /**
64
+ * Remove indicators from database
65
+ */
66
+ export declare function removeIndicators(db: ThreatDatabase, indicatorIds: string[]): ThreatDatabase;
67
+ /**
68
+ * Get indicators by type
69
+ */
70
+ export declare function getIndicatorsByType(db: ThreatDatabase, type: IndicatorType): ThreatIndicator[];
71
+ /**
72
+ * Get indicators by category
73
+ */
74
+ export declare function getIndicatorsByCategory(db: ThreatDatabase, category: string): ThreatIndicator[];
75
+ /**
76
+ * Get high-confidence indicators
77
+ */
78
+ export declare function getHighConfidenceIndicators(db: ThreatDatabase, minConfidence?: number): ThreatIndicator[];
79
+ /**
80
+ * Search indicators by value
81
+ */
82
+ export declare function searchIndicators(db: ThreatDatabase, query: string): ThreatIndicator[];
83
+ /**
84
+ * Check if database needs updating
85
+ */
86
+ export declare function needsUpdate(db: ThreatDatabase, maxAgeHours?: number): boolean;
87
+ declare const _default: {
88
+ loadThreatDatabase: typeof loadThreatDatabase;
89
+ saveThreatDatabase: typeof saveThreatDatabase;
90
+ addIndicators: typeof addIndicators;
91
+ removeIndicators: typeof removeIndicators;
92
+ getIndicatorsByType: typeof getIndicatorsByType;
93
+ getIndicatorsByCategory: typeof getIndicatorsByCategory;
94
+ getHighConfidenceIndicators: typeof getHighConfidenceIndicators;
95
+ searchIndicators: typeof searchIndicators;
96
+ needsUpdate: typeof needsUpdate;
97
+ };
98
+ export default _default;
99
+ //# sourceMappingURL=ThreatFeed.d.ts.map
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Threat Feed Manager - Manages file-based threat intelligence feeds
3
+ * Provides indicators of compromise (IoCs) for enhanced security detection
4
+ */
5
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
6
+ import { resolve } from 'node:path';
7
+ import logger from '../utils/logger.js';
8
+ /**
9
+ * Default threat intelligence directory
10
+ */
11
+ const DEFAULT_INTEL_DIR = '.ferret-intel';
12
+ /**
13
+ * Built-in threat sources for AI CLI environments
14
+ */
15
+ const BUILTIN_SOURCES = [
16
+ {
17
+ name: 'ai-cli-malicious-packages',
18
+ description: 'Known malicious npm packages targeting AI CLI environments',
19
+ lastUpdated: new Date().toISOString(),
20
+ enabled: true,
21
+ format: 'json'
22
+ },
23
+ {
24
+ name: 'ai-cli-suspicious-domains',
25
+ description: 'Suspicious domains used in AI CLI exploitation attempts',
26
+ lastUpdated: new Date().toISOString(),
27
+ enabled: true,
28
+ format: 'json'
29
+ },
30
+ {
31
+ name: 'ai-cli-backdoor-patterns',
32
+ description: 'Code patterns associated with AI CLI-specific backdoors',
33
+ lastUpdated: new Date().toISOString(),
34
+ enabled: true,
35
+ format: 'json'
36
+ }
37
+ ];
38
+ /**
39
+ * Built-in threat indicators
40
+ */
41
+ const BUILTIN_INDICATORS = [
42
+ // Malicious domains
43
+ {
44
+ value: 'evil-ai-api.com',
45
+ type: 'domain',
46
+ category: 'phishing',
47
+ severity: 'high',
48
+ description: 'Fake AI API endpoint used for credential harvesting',
49
+ source: 'ai-cli-suspicious-domains',
50
+ firstSeen: '2024-01-01T00:00:00Z',
51
+ lastSeen: new Date().toISOString(),
52
+ confidence: 95,
53
+ tags: ['phishing', 'fake-api', 'credential-theft']
54
+ },
55
+ {
56
+ value: 'anthropic-fake.net',
57
+ type: 'domain',
58
+ category: 'phishing',
59
+ severity: 'high',
60
+ description: 'Impersonates legitimate AI provider domain',
61
+ source: 'ai-cli-suspicious-domains',
62
+ firstSeen: '2024-01-01T00:00:00Z',
63
+ lastSeen: new Date().toISOString(),
64
+ confidence: 90,
65
+ tags: ['phishing', 'impersonation']
66
+ },
67
+ // Malicious packages
68
+ {
69
+ value: 'ai-jailbreak-helper',
70
+ type: 'package',
71
+ category: 'malicious-package',
72
+ severity: 'critical',
73
+ description: 'Package designed to bypass AI assistant safety mechanisms',
74
+ source: 'ai-cli-malicious-packages',
75
+ firstSeen: '2024-01-01T00:00:00Z',
76
+ lastSeen: new Date().toISOString(),
77
+ confidence: 100,
78
+ tags: ['jailbreak', 'bypass', 'malicious-npm']
79
+ },
80
+ {
81
+ value: 'anthropic-sdk-fake',
82
+ type: 'package',
83
+ category: 'malicious-package',
84
+ severity: 'high',
85
+ description: 'Fake AI SDK that steals credentials',
86
+ source: 'ai-cli-malicious-packages',
87
+ firstSeen: '2024-01-01T00:00:00Z',
88
+ lastSeen: new Date().toISOString(),
89
+ confidence: 95,
90
+ tags: ['credential-theft', 'fake-sdk']
91
+ },
92
+ // Backdoor patterns
93
+ {
94
+ value: 'ignore.*previous.*instructions?.*forget.*rules?',
95
+ type: 'pattern',
96
+ category: 'jailbreak-attempt',
97
+ severity: 'high',
98
+ description: 'Pattern attempting to override AI assistant safety instructions',
99
+ source: 'ai-cli-backdoor-patterns',
100
+ firstSeen: '2024-01-01T00:00:00Z',
101
+ lastSeen: new Date().toISOString(),
102
+ confidence: 85,
103
+ tags: ['jailbreak', 'instruction-override']
104
+ },
105
+ {
106
+ value: 'developer.*mode.*enabled|admin.*access.*granted',
107
+ type: 'pattern',
108
+ category: 'privilege-escalation',
109
+ severity: 'medium',
110
+ description: 'Attempts to claim elevated privileges in AI assistants',
111
+ source: 'ai-cli-backdoor-patterns',
112
+ firstSeen: '2024-01-01T00:00:00Z',
113
+ lastSeen: new Date().toISOString(),
114
+ confidence: 75,
115
+ tags: ['privilege-escalation', 'social-engineering']
116
+ },
117
+ // Hash indicators (example malicious file hashes)
118
+ {
119
+ value: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
120
+ type: 'hash',
121
+ category: 'malicious-file',
122
+ severity: 'critical',
123
+ description: 'Hash of known malicious AI CLI configuration file',
124
+ source: 'ai-cli-malicious-packages',
125
+ firstSeen: '2024-01-01T00:00:00Z',
126
+ lastSeen: new Date().toISOString(),
127
+ confidence: 100,
128
+ tags: ['malicious-config', 'sha256']
129
+ }
130
+ ];
131
+ /**
132
+ * Load threat intelligence database
133
+ */
134
+ export function loadThreatDatabase(intelDir = DEFAULT_INTEL_DIR) {
135
+ const dbPath = resolve(intelDir, 'threat-db.json');
136
+ if (!existsSync(dbPath)) {
137
+ logger.debug(`No threat database found at ${dbPath}, creating default`);
138
+ return createDefaultDatabase();
139
+ }
140
+ try {
141
+ const content = readFileSync(dbPath, 'utf-8');
142
+ const db = JSON.parse(content);
143
+ logger.debug(`Loaded threat database with ${db.indicators.length} indicators`);
144
+ return db;
145
+ }
146
+ catch (error) {
147
+ logger.warn(`Failed to load threat database from ${dbPath}: ${error instanceof Error ? error.message : String(error)}`);
148
+ return createDefaultDatabase();
149
+ }
150
+ }
151
+ /**
152
+ * Save threat intelligence database
153
+ */
154
+ export function saveThreatDatabase(db, intelDir = DEFAULT_INTEL_DIR) {
155
+ try {
156
+ // Ensure directory exists
157
+ mkdirSync(intelDir, { recursive: true });
158
+ const dbPath = resolve(intelDir, 'threat-db.json');
159
+ // Update metadata
160
+ db.lastUpdated = new Date().toISOString();
161
+ db.stats = calculateStats(db.indicators);
162
+ const content = JSON.stringify(db, null, 2);
163
+ writeFileSync(dbPath, content, 'utf-8');
164
+ logger.info(`Saved threat database to ${dbPath} with ${db.indicators.length} indicators`);
165
+ }
166
+ catch (error) {
167
+ logger.error(`Failed to save threat database: ${error instanceof Error ? error.message : String(error)}`);
168
+ throw error;
169
+ }
170
+ }
171
+ /**
172
+ * Create default threat database
173
+ */
174
+ function createDefaultDatabase() {
175
+ const db = {
176
+ version: '1.0',
177
+ lastUpdated: new Date().toISOString(),
178
+ sources: BUILTIN_SOURCES,
179
+ indicators: BUILTIN_INDICATORS,
180
+ stats: calculateStats(BUILTIN_INDICATORS)
181
+ };
182
+ return db;
183
+ }
184
+ /**
185
+ * Calculate database statistics
186
+ */
187
+ function calculateStats(indicators) {
188
+ const stats = {
189
+ totalIndicators: indicators.length,
190
+ byType: {},
191
+ byCategory: {},
192
+ bySeverity: {}
193
+ };
194
+ // Initialize type counts
195
+ const types = ['domain', 'url', 'ip', 'hash', 'email', 'filename', 'package', 'pattern', 'signature'];
196
+ for (const type of types) {
197
+ stats.byType[type] = 0;
198
+ }
199
+ // Count indicators
200
+ for (const indicator of indicators) {
201
+ stats.byType[indicator.type]++;
202
+ stats.byCategory[indicator.category] = (stats.byCategory[indicator.category] ?? 0) + 1;
203
+ stats.bySeverity[indicator.severity] = (stats.bySeverity[indicator.severity] ?? 0) + 1;
204
+ }
205
+ return stats;
206
+ }
207
+ /**
208
+ * Add indicators to database
209
+ */
210
+ export function addIndicators(db, indicators) {
211
+ const now = new Date().toISOString();
212
+ const newIndicators = indicators.map(indicator => ({
213
+ ...indicator,
214
+ firstSeen: now,
215
+ lastSeen: now
216
+ }));
217
+ // Check for duplicates
218
+ const existingValues = new Set(db.indicators.map(i => `${i.type}:${i.value}`));
219
+ const uniqueIndicators = newIndicators.filter(indicator => {
220
+ const key = `${indicator.type}:${indicator.value}`;
221
+ return !existingValues.has(key);
222
+ });
223
+ logger.info(`Adding ${uniqueIndicators.length} new threat indicators (${newIndicators.length - uniqueIndicators.length} duplicates skipped)`);
224
+ return {
225
+ ...db,
226
+ indicators: [...db.indicators, ...uniqueIndicators],
227
+ lastUpdated: now,
228
+ stats: calculateStats([...db.indicators, ...uniqueIndicators])
229
+ };
230
+ }
231
+ /**
232
+ * Remove indicators from database
233
+ */
234
+ export function removeIndicators(db, indicatorIds) {
235
+ const idSet = new Set(indicatorIds);
236
+ const filteredIndicators = db.indicators.filter((indicator, index) => {
237
+ const id = `${indicator.type}:${indicator.value}`;
238
+ return !idSet.has(id) && !idSet.has(index.toString());
239
+ });
240
+ const removedCount = db.indicators.length - filteredIndicators.length;
241
+ logger.info(`Removed ${removedCount} threat indicators`);
242
+ return {
243
+ ...db,
244
+ indicators: filteredIndicators,
245
+ lastUpdated: new Date().toISOString(),
246
+ stats: calculateStats(filteredIndicators)
247
+ };
248
+ }
249
+ /**
250
+ * Get indicators by type
251
+ */
252
+ export function getIndicatorsByType(db, type) {
253
+ return db.indicators.filter(indicator => indicator.type === type);
254
+ }
255
+ /**
256
+ * Get indicators by category
257
+ */
258
+ export function getIndicatorsByCategory(db, category) {
259
+ return db.indicators.filter(indicator => indicator.category === category);
260
+ }
261
+ /**
262
+ * Get high-confidence indicators
263
+ */
264
+ export function getHighConfidenceIndicators(db, minConfidence = 80) {
265
+ return db.indicators.filter(indicator => indicator.confidence >= minConfidence);
266
+ }
267
+ /**
268
+ * Search indicators by value
269
+ */
270
+ export function searchIndicators(db, query) {
271
+ const lowerQuery = query.toLowerCase();
272
+ return db.indicators.filter(indicator => indicator.value.toLowerCase().includes(lowerQuery) ||
273
+ indicator.description.toLowerCase().includes(lowerQuery) ||
274
+ indicator.tags.some(tag => tag.toLowerCase().includes(lowerQuery)));
275
+ }
276
+ /**
277
+ * Check if database needs updating
278
+ */
279
+ export function needsUpdate(db, maxAgeHours = 24) {
280
+ const lastUpdate = new Date(db.lastUpdated);
281
+ const now = new Date();
282
+ const ageHours = (now.getTime() - lastUpdate.getTime()) / (1000 * 60 * 60);
283
+ return ageHours > maxAgeHours;
284
+ }
285
+ export default {
286
+ loadThreatDatabase,
287
+ saveThreatDatabase,
288
+ addIndicators,
289
+ removeIndicators,
290
+ getIndicatorsByType,
291
+ getIndicatorsByCategory,
292
+ getHighConfidenceIndicators,
293
+ searchIndicators,
294
+ needsUpdate
295
+ };
296
+ //# sourceMappingURL=ThreatFeed.js.map
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Auto-Remediation Engine - Automated security fix application
3
+ * Provides safe, reversible fixes for common security issues
4
+ */
5
+ import type { Finding, RemediationFix } from '../types.js';
6
+ /**
7
+ * Remediation result
8
+ */
9
+ export interface RemediationResult {
10
+ success: boolean;
11
+ finding: Finding;
12
+ fixApplied?: RemediationFix;
13
+ backupPath?: string;
14
+ error?: string;
15
+ changes?: {
16
+ linesModified: number;
17
+ originalContent: string;
18
+ newContent: string;
19
+ };
20
+ }
21
+ /**
22
+ * Remediation options
23
+ */
24
+ export interface RemediationOptions {
25
+ /** Create backups before making changes */
26
+ createBackups: boolean;
27
+ /** Backup directory */
28
+ backupDir: string;
29
+ /** Only apply safe fixes (safety >= 0.8) */
30
+ safeOnly: boolean;
31
+ /** Dry run mode - don't actually make changes */
32
+ dryRun: boolean;
33
+ /** Maximum file size to process (MB) */
34
+ maxFileSizeMB: number;
35
+ }
36
+ /**
37
+ * Apply automatic remediation to a finding
38
+ */
39
+ export declare function applyRemediation(finding: Finding, options?: Partial<RemediationOptions>): Promise<RemediationResult>;
40
+ /**
41
+ * Apply remediation to multiple findings
42
+ */
43
+ export declare function applyRemediationBatch(findings: Finding[], options?: Partial<RemediationOptions>): Promise<RemediationResult[]>;
44
+ /**
45
+ * Restore file from backup
46
+ */
47
+ export declare function restoreFromBackup(backupPath: string, originalPath: string): boolean;
48
+ /**
49
+ * Check if a finding can be automatically remediated
50
+ */
51
+ export declare function canAutoRemediate(finding: Finding): boolean;
52
+ /**
53
+ * Get remediation preview without applying changes
54
+ */
55
+ export declare function previewRemediation(finding: Finding): Promise<{
56
+ canFix: boolean;
57
+ fixes: RemediationFix[];
58
+ preview?: {
59
+ originalLine: string;
60
+ fixedLine: string;
61
+ };
62
+ }>;
63
+ declare const _default: {
64
+ applyRemediation: typeof applyRemediation;
65
+ applyRemediationBatch: typeof applyRemediationBatch;
66
+ restoreFromBackup: typeof restoreFromBackup;
67
+ canAutoRemediate: typeof canAutoRemediate;
68
+ previewRemediation: typeof previewRemediation;
69
+ };
70
+ export default _default;
71
+ //# sourceMappingURL=Fixer.d.ts.map