aura-security 1.0.1 → 1.0.2
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.
|
@@ -66,7 +66,18 @@ const FALSE_POSITIVE_DIRS = [
|
|
|
66
66
|
'/thirdparty/',
|
|
67
67
|
'/external/',
|
|
68
68
|
'/dummy/',
|
|
69
|
-
'/fake/'
|
|
69
|
+
'/fake/',
|
|
70
|
+
'/data/',
|
|
71
|
+
'/scripts/data/',
|
|
72
|
+
'/seeds/',
|
|
73
|
+
'/seed/',
|
|
74
|
+
'/migrations/',
|
|
75
|
+
'/migration/',
|
|
76
|
+
'/index_constituents/',
|
|
77
|
+
'/token-list/',
|
|
78
|
+
'/tokenlist/',
|
|
79
|
+
'/verified-tokens/',
|
|
80
|
+
'/validated-tokens/'
|
|
70
81
|
];
|
|
71
82
|
// File name patterns that indicate test/example data (not real secrets)
|
|
72
83
|
const TEST_FILE_PATTERNS = [
|
|
@@ -108,6 +119,8 @@ const SKIP_RULES_IN_FILE_TYPES = {
|
|
|
108
119
|
'.md': ['generic-api-key', 'curl-auth-header'],
|
|
109
120
|
'.rst': ['generic-api-key', 'curl-auth-header'],
|
|
110
121
|
'.txt': ['generic-api-key'],
|
|
122
|
+
// JSON files often contain token lists, address registries, config data - not real secrets
|
|
123
|
+
'.json': ['generic-api-key', 'aws-access-token', 'private-key'],
|
|
111
124
|
};
|
|
112
125
|
// Run gitleaks for secrets detection
|
|
113
126
|
function runGitleaks(targetPath) {
|
|
@@ -153,8 +166,17 @@ function runGitleaks(targetPath) {
|
|
|
153
166
|
const fileExt = extname(fileName).toLowerCase();
|
|
154
167
|
const skipRulesForExt = SKIP_RULES_IN_FILE_TYPES[fileExt] || [];
|
|
155
168
|
const isRuleSkippedForFileType = skipRulesForExt.includes(ruleId);
|
|
169
|
+
// Filter out JSON data files that contain token lists / address registries
|
|
170
|
+
// (Solana base58 addresses get flagged as API keys by gitleaks)
|
|
171
|
+
const isJsonDataFile = fileExt === '.json' && (/token[-_]?list/i.test(filePath) ||
|
|
172
|
+
/address(es)?[-_]?(list|registry)/i.test(filePath) ||
|
|
173
|
+
/constituents/i.test(filePath) ||
|
|
174
|
+
/verified[-_]?tokens/i.test(filePath) ||
|
|
175
|
+
/validated[-_]?tokens/i.test(filePath) ||
|
|
176
|
+
/mint(s)?[-_]?(list|registry)/i.test(filePath) ||
|
|
177
|
+
/registry\.json$/i.test(filePath));
|
|
156
178
|
// Skip if any false positive indicator matches
|
|
157
|
-
if (isExcludedFile || isInFalsePositiveDir || isTestFile || isFalsePositiveRule || isRuleSkippedForFileType) {
|
|
179
|
+
if (isExcludedFile || isInFalsePositiveDir || isTestFile || isFalsePositiveRule || isRuleSkippedForFileType || isJsonDataFile) {
|
|
158
180
|
filteredCount++;
|
|
159
181
|
continue;
|
|
160
182
|
}
|
|
@@ -166,13 +188,34 @@ function runGitleaks(targetPath) {
|
|
|
166
188
|
severity: finding.Entropy > 4.5 ? 'critical' : 'high'
|
|
167
189
|
});
|
|
168
190
|
}
|
|
191
|
+
// Post-processing: if a single JSON file has 10+ findings, it's almost certainly
|
|
192
|
+
// a data/registry file (token lists, address mappings) not real leaked secrets
|
|
193
|
+
const fileCounts = new Map();
|
|
194
|
+
for (const f of findings) {
|
|
195
|
+
if (f.file.toLowerCase().endsWith('.json')) {
|
|
196
|
+
fileCounts.set(f.file, (fileCounts.get(f.file) || 0) + 1);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const bulkJsonFiles = new Set();
|
|
200
|
+
for (const [file, count] of fileCounts) {
|
|
201
|
+
if (count >= 10) {
|
|
202
|
+
bulkJsonFiles.add(file);
|
|
203
|
+
filteredCount += count;
|
|
204
|
+
console.log(`[SCANNER] Filtered ${count} findings from ${basename(file)} (bulk data file)`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (bulkJsonFiles.size > 0) {
|
|
208
|
+
const beforeCount = findings.length;
|
|
209
|
+
findings.splice(0, findings.length, ...findings.filter(f => !bulkJsonFiles.has(f.file)));
|
|
210
|
+
console.log(`[SCANNER] Removed ${beforeCount - findings.length} bulk JSON false positives`);
|
|
211
|
+
}
|
|
169
212
|
// Cleanup
|
|
170
213
|
try {
|
|
171
214
|
rmSync(reportPath);
|
|
172
215
|
}
|
|
173
216
|
catch { }
|
|
174
217
|
if (filteredCount > 0) {
|
|
175
|
-
console.log(`[SCANNER] Filtered ${filteredCount} false positives (test files, examples, lock files)`);
|
|
218
|
+
console.log(`[SCANNER] Filtered ${filteredCount} false positives (test files, examples, lock files, data files)`);
|
|
176
219
|
}
|
|
177
220
|
}
|
|
178
221
|
console.log(`[SCANNER] gitleaks found ${findings.length} secrets`);
|
|
@@ -777,10 +820,20 @@ const SECRET_PATTERNS = [
|
|
|
777
820
|
// OpenAI API Key
|
|
778
821
|
{ name: 'OpenAI Key', regex: /sk-[A-Za-z0-9]{32,}/g, severity: 'high' },
|
|
779
822
|
];
|
|
780
|
-
// Files/patterns to SKIP for secret scanning (test files, examples,
|
|
823
|
+
// Files/patterns to SKIP for secret scanning (test files, examples, lock files, data files)
|
|
781
824
|
const SKIP_SECRET_SCAN_PATTERNS = [
|
|
825
|
+
// Test/example files
|
|
782
826
|
/example/i, /sample/i, /test/i, /mock/i, /fixture/i, /\.test\./i, /\.spec\./i,
|
|
783
|
-
|
|
827
|
+
// Build artifacts
|
|
828
|
+
/\.d\.ts$/, /\.map$/, /\.min\./,
|
|
829
|
+
// Lock files (contain hashes that trigger false positives, never contain real secrets)
|
|
830
|
+
/package-lock\.json$/i, /pnpm-lock\.yaml$/i, /yarn\.lock$/i, /Cargo\.lock$/i, /composer\.lock$/i, /Gemfile\.lock$/i,
|
|
831
|
+
// Template/example env files (placeholders, not real secrets)
|
|
832
|
+
/\.example$/i, /\.template$/i, /\.sample$/i,
|
|
833
|
+
// Data directories (contain public addresses, not secrets)
|
|
834
|
+
/\/data\//i, /\/fixtures?\//i, /\/seeds?\//i, /\/migrations?\//i,
|
|
835
|
+
// Index/constituent data files (stock symbols, token lists etc.)
|
|
836
|
+
/index_constituents/i, /token-?list/i, /verified-tokens/i, /validated-tokens/i,
|
|
784
837
|
];
|
|
785
838
|
// Files to scan for secrets
|
|
786
839
|
const FILES_TO_SCAN = [
|
|
@@ -1408,9 +1461,26 @@ export class LocalScanner {
|
|
|
1408
1461
|
if (stats.size > 1024 * 1024)
|
|
1409
1462
|
return findings;
|
|
1410
1463
|
const content = readFileSync(filePath, 'utf-8');
|
|
1464
|
+
// Skip JSON files that are clearly data (token lists, address registries, etc.)
|
|
1465
|
+
// These contain public blockchain addresses that regex misidentifies as secrets
|
|
1466
|
+
if (fileName.endsWith('.json')) {
|
|
1467
|
+
// If a JSON file has "tokens", "addresses", "mints", "symbols" keys, it's data
|
|
1468
|
+
if (/["'](tokens|addresses|mints|symbols|constituents|verified|validated)["']\s*:/i.test(content)) {
|
|
1469
|
+
return findings;
|
|
1470
|
+
}
|
|
1471
|
+
// If JSON file has more than 100 similar-looking base58 values, it's a token/address list
|
|
1472
|
+
const base58Matches = content.match(/["'][1-9A-HJ-NP-Za-km-z]{32,44}["']/g);
|
|
1473
|
+
if (base58Matches && base58Matches.length > 50) {
|
|
1474
|
+
return findings;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1411
1477
|
const lines = content.split('\n');
|
|
1412
1478
|
for (let i = 0; i < lines.length; i++) {
|
|
1413
1479
|
const line = lines[i];
|
|
1480
|
+
// Skip lines that are clearly placeholder/example values
|
|
1481
|
+
if (/your[_-]?(?:api[_-]?key|token|secret)|REPLACE[_-]?ME|TODO|CHANGEME|xxxx|placeholder/i.test(line)) {
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1414
1484
|
for (const pattern of SECRET_PATTERNS) {
|
|
1415
1485
|
pattern.regex.lastIndex = 0;
|
|
1416
1486
|
const match = pattern.regex.exec(line);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aura-security",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "AI-powered security scanner with 9-agent swarm. Detect secrets, vulnerabilities, attack paths. CLI, API, or cloud dashboard at app.aurasecurity.io",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|