pompelmi 0.19.0 → 0.21.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.
- package/README.md +283 -47
- package/dist/pompelmi.cjs +472 -7
- package/dist/pompelmi.cjs.map +1 -1
- package/dist/pompelmi.esm.js +445 -8
- package/dist/pompelmi.esm.js.map +1 -1
- package/dist/types/engines/dynamic-taint.d.ts +102 -0
- package/dist/types/engines/hybrid-orchestrator.d.ts +65 -0
- package/dist/types/engines/hybrid-taint-integration.d.ts +129 -0
- package/dist/types/engines/taint-policies.d.ts +84 -0
- package/dist/types/hipaa-compliance.d.ts +110 -0
- package/dist/types/presets.d.ts +15 -3
- package/dist/types/types/decompilation.d.ts +96 -0
- package/dist/types/types/taint-tracking.d.ts +495 -0
- package/dist/types/types.d.ts +2 -1
- package/package.json +5 -7
package/dist/pompelmi.cjs
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
var os = require('os');
|
|
5
|
+
var path = require('path');
|
|
6
|
+
|
|
7
|
+
function _interopNamespaceDefault(e) {
|
|
8
|
+
var n = Object.create(null);
|
|
9
|
+
if (e) {
|
|
10
|
+
Object.keys(e).forEach(function (k) {
|
|
11
|
+
if (k !== 'default') {
|
|
12
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
13
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return e[k]; }
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
n.default = e;
|
|
21
|
+
return Object.freeze(n);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto);
|
|
25
|
+
var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
|
|
26
|
+
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
27
|
+
|
|
3
28
|
function toScanFn(s) {
|
|
4
29
|
return (typeof s === "function" ? s : s.scan);
|
|
5
30
|
}
|
|
@@ -19,12 +44,98 @@ function composeScanners(...scanners) {
|
|
|
19
44
|
return all;
|
|
20
45
|
};
|
|
21
46
|
}
|
|
22
|
-
function createPresetScanner(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
47
|
+
function createPresetScanner(preset, opts = {}) {
|
|
48
|
+
const scanners = [];
|
|
49
|
+
// Add decompilation scanners based on preset
|
|
50
|
+
if (preset === 'decompilation-basic' || preset === 'decompilation-deep' ||
|
|
51
|
+
preset === 'malware-analysis' || opts.enableDecompilation) {
|
|
52
|
+
const depth = preset === 'decompilation-deep' ? 'deep' :
|
|
53
|
+
preset === 'decompilation-basic' ? 'basic' :
|
|
54
|
+
opts.decompilationDepth || 'basic';
|
|
55
|
+
if (!opts.decompilationEngine || opts.decompilationEngine === 'binaryninja-hlil' || opts.decompilationEngine === 'both') {
|
|
56
|
+
try {
|
|
57
|
+
// Dynamic import to avoid bundling issues
|
|
58
|
+
import('@pompelmi/engine-binaryninja').then(({ createBinaryNinjaScanner }) => {
|
|
59
|
+
const binjaScanner = createBinaryNinjaScanner({
|
|
60
|
+
timeout: opts.decompilationTimeout || opts.timeout || 30000,
|
|
61
|
+
depth,
|
|
62
|
+
pythonPath: opts.pythonPath,
|
|
63
|
+
binaryNinjaPath: opts.binaryNinjaPath
|
|
64
|
+
});
|
|
65
|
+
scanners.push(binjaScanner);
|
|
66
|
+
}).catch(() => {
|
|
67
|
+
// Binary Ninja engine not available
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Engine not installed
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!opts.decompilationEngine || opts.decompilationEngine === 'ghidra-pcode' || opts.decompilationEngine === 'both') {
|
|
75
|
+
try {
|
|
76
|
+
// Dynamic import for Ghidra engine (when implemented)
|
|
77
|
+
import('@pompelmi/engine-ghidra').then(({ createGhidraScanner }) => {
|
|
78
|
+
const ghidraScanner = createGhidraScanner({
|
|
79
|
+
timeout: opts.decompilationTimeout || opts.timeout || 30000,
|
|
80
|
+
depth,
|
|
81
|
+
ghidraPath: opts.ghidraPath,
|
|
82
|
+
analyzeHeadless: opts.analyzeHeadless
|
|
83
|
+
});
|
|
84
|
+
scanners.push(ghidraScanner);
|
|
85
|
+
}).catch(() => {
|
|
86
|
+
// Ghidra engine not available
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Engine not installed
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Add other scanners for advanced presets
|
|
95
|
+
if (preset === 'advanced' || preset === 'malware-analysis') {
|
|
96
|
+
// Add heuristics scanner
|
|
97
|
+
try {
|
|
98
|
+
const { CommonHeuristicsScanner } = require('./scanners/common-heuristics');
|
|
99
|
+
scanners.push(new CommonHeuristicsScanner());
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// Heuristics not available
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (scanners.length === 0) {
|
|
106
|
+
// Fallback scanner that returns no matches
|
|
107
|
+
return async (_input, _ctx) => {
|
|
108
|
+
return [];
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return composeScanners(...scanners);
|
|
27
112
|
}
|
|
113
|
+
// Preset configurations
|
|
114
|
+
const PRESET_CONFIGS = {
|
|
115
|
+
'basic': {
|
|
116
|
+
timeout: 10000
|
|
117
|
+
},
|
|
118
|
+
'advanced': {
|
|
119
|
+
timeout: 30000,
|
|
120
|
+
enableDecompilation: false
|
|
121
|
+
},
|
|
122
|
+
'malware-analysis': {
|
|
123
|
+
timeout: 60000,
|
|
124
|
+
enableDecompilation: true,
|
|
125
|
+
decompilationEngine: 'both',
|
|
126
|
+
decompilationDepth: 'deep'
|
|
127
|
+
},
|
|
128
|
+
'decompilation-basic': {
|
|
129
|
+
timeout: 30000,
|
|
130
|
+
enableDecompilation: true,
|
|
131
|
+
decompilationDepth: 'basic'
|
|
132
|
+
},
|
|
133
|
+
'decompilation-deep': {
|
|
134
|
+
timeout: 120000,
|
|
135
|
+
enableDecompilation: true,
|
|
136
|
+
decompilationDepth: 'deep'
|
|
137
|
+
}
|
|
138
|
+
};
|
|
28
139
|
|
|
29
140
|
/** Mappa veloce estensione -> mime (basic) */
|
|
30
141
|
function guessMimeByExt(name) {
|
|
@@ -61,13 +172,13 @@ function toYaraMatches(ms) {
|
|
|
61
172
|
/** Scan di bytes (browser/node) usando preset (default: zip-basic) */
|
|
62
173
|
async function scanBytes(input, opts = {}) {
|
|
63
174
|
const t0 = Date.now();
|
|
64
|
-
opts.preset ?? 'zip-basic';
|
|
175
|
+
const preset = opts.preset ?? 'zip-basic';
|
|
65
176
|
const ctx = {
|
|
66
177
|
...opts.ctx,
|
|
67
178
|
mimeType: opts.ctx?.mimeType ?? guessMimeByExt(opts.ctx?.filename),
|
|
68
179
|
size: opts.ctx?.size ?? input.byteLength,
|
|
69
180
|
};
|
|
70
|
-
const scanFn = createPresetScanner();
|
|
181
|
+
const scanFn = createPresetScanner(preset);
|
|
71
182
|
const matchesH = await (typeof scanFn === "function" ? scanFn : scanFn.scan)(input, ctx);
|
|
72
183
|
const matches = toYaraMatches(matchesH);
|
|
73
184
|
const verdict = computeVerdict(matches);
|
|
@@ -2110,6 +2221,353 @@ async function scanFilesWithRemoteYara(files, rulesSource, remote) {
|
|
|
2110
2221
|
return results;
|
|
2111
2222
|
}
|
|
2112
2223
|
|
|
2224
|
+
/** Decompilation-specific types for Pompelmi */
|
|
2225
|
+
const SUSPICIOUS_PATTERNS = [
|
|
2226
|
+
{
|
|
2227
|
+
name: 'syscall_direct',
|
|
2228
|
+
description: 'Direct system call without library wrapper',
|
|
2229
|
+
severity: 'medium',
|
|
2230
|
+
pattern: /syscall|sysenter|int\s+0x80/i
|
|
2231
|
+
},
|
|
2232
|
+
{
|
|
2233
|
+
name: 'process_injection',
|
|
2234
|
+
description: 'Process injection techniques',
|
|
2235
|
+
severity: 'high',
|
|
2236
|
+
pattern: /CreateRemoteThread|WriteProcessMemory|VirtualAllocEx/i
|
|
2237
|
+
},
|
|
2238
|
+
{
|
|
2239
|
+
name: 'anti_debug',
|
|
2240
|
+
description: 'Anti-debugging techniques',
|
|
2241
|
+
severity: 'medium',
|
|
2242
|
+
pattern: /IsDebuggerPresent|CheckRemoteDebuggerPresent|OutputDebugString/i
|
|
2243
|
+
},
|
|
2244
|
+
{
|
|
2245
|
+
name: 'obfuscation_xor',
|
|
2246
|
+
description: 'XOR-based obfuscation pattern',
|
|
2247
|
+
severity: 'medium',
|
|
2248
|
+
pattern: /xor.*0x[0-9a-f]+.*xor/i
|
|
2249
|
+
},
|
|
2250
|
+
{
|
|
2251
|
+
name: 'crypto_constants',
|
|
2252
|
+
description: 'Cryptographic constants',
|
|
2253
|
+
severity: 'low',
|
|
2254
|
+
pattern: /0x67452301|0xefcdab89|0x98badcfe|0x10325476/i
|
|
2255
|
+
}
|
|
2256
|
+
];
|
|
2257
|
+
|
|
2258
|
+
/**
|
|
2259
|
+
* HIPAA Compliance Module for Pompelmi
|
|
2260
|
+
*
|
|
2261
|
+
* This module provides comprehensive HIPAA compliance features for healthcare environments
|
|
2262
|
+
* where Pompelmi is used to analyze potentially compromised systems containing PHI.
|
|
2263
|
+
*
|
|
2264
|
+
* Key protections:
|
|
2265
|
+
* - Data sanitization and redaction
|
|
2266
|
+
* - Secure temporary file handling
|
|
2267
|
+
* - Audit logging
|
|
2268
|
+
* - Memory protection
|
|
2269
|
+
* - Error message sanitization
|
|
2270
|
+
*/
|
|
2271
|
+
class HipaaComplianceManager {
|
|
2272
|
+
constructor(config) {
|
|
2273
|
+
this.auditEvents = [];
|
|
2274
|
+
this.config = {
|
|
2275
|
+
enabled: true,
|
|
2276
|
+
sanitizeErrors: true,
|
|
2277
|
+
sanitizeFilenames: true,
|
|
2278
|
+
encryptTempFiles: true,
|
|
2279
|
+
memoryProtection: true,
|
|
2280
|
+
requireSecureTransport: true,
|
|
2281
|
+
...config
|
|
2282
|
+
};
|
|
2283
|
+
this.sessionId = this.generateSessionId();
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* Sanitize filename to prevent PHI leakage in logs
|
|
2287
|
+
*/
|
|
2288
|
+
sanitizeFilename(filename) {
|
|
2289
|
+
if (!this.config.enabled || !this.config.sanitizeFilenames || !filename) {
|
|
2290
|
+
return filename || 'unknown';
|
|
2291
|
+
}
|
|
2292
|
+
// Remove potentially sensitive path information
|
|
2293
|
+
const basename = path__namespace.basename(filename);
|
|
2294
|
+
// Hash the filename to create a consistent but non-revealing identifier
|
|
2295
|
+
const hash = crypto__namespace.createHash('sha256').update(basename).digest('hex').substring(0, 8);
|
|
2296
|
+
// Preserve file extension for analysis purposes
|
|
2297
|
+
const ext = path__namespace.extname(basename);
|
|
2298
|
+
return `file_${hash}${ext}`;
|
|
2299
|
+
}
|
|
2300
|
+
/**
|
|
2301
|
+
* Sanitize error messages to prevent PHI exposure
|
|
2302
|
+
*/
|
|
2303
|
+
sanitizeError(error) {
|
|
2304
|
+
if (!this.config.enabled || !this.config.sanitizeErrors) {
|
|
2305
|
+
return typeof error === 'string' ? error : error.message;
|
|
2306
|
+
}
|
|
2307
|
+
const message = typeof error === 'string' ? error : error.message;
|
|
2308
|
+
// Remove common patterns that might contain PHI
|
|
2309
|
+
let sanitized = message
|
|
2310
|
+
// Remove file paths
|
|
2311
|
+
.replace(/[A-Za-z]:\\\\[^\\s]+/g, '[REDACTED_PATH]')
|
|
2312
|
+
.replace(/\/[^\\s]+/g, '[REDACTED_PATH]')
|
|
2313
|
+
// Remove potential patient identifiers (numbers that could be MRNs, SSNs)
|
|
2314
|
+
.replace(/\\b\\d{3}-?\\d{2}-?\\d{4}\\b/g, '[REDACTED_ID]')
|
|
2315
|
+
.replace(/\\b\\d{6,}\\b/g, '[REDACTED_ID]')
|
|
2316
|
+
// Remove email addresses
|
|
2317
|
+
.replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g, '[REDACTED_EMAIL]')
|
|
2318
|
+
// Remove potential names (capitalize words in error messages)
|
|
2319
|
+
.replace(/\\b[A-Z][a-z]+\\s+[A-Z][a-z]+\\b/g, '[REDACTED_NAME]')
|
|
2320
|
+
// Remove IP addresses
|
|
2321
|
+
.replace(/\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g, '[REDACTED_IP]');
|
|
2322
|
+
return sanitized;
|
|
2323
|
+
}
|
|
2324
|
+
/**
|
|
2325
|
+
* Create secure temporary file path with encryption if enabled
|
|
2326
|
+
*/
|
|
2327
|
+
createSecureTempPath(prefix = 'pompelmi') {
|
|
2328
|
+
if (!this.config.enabled) {
|
|
2329
|
+
return path__namespace.join(os__namespace.tmpdir(), `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
2330
|
+
}
|
|
2331
|
+
// Use cryptographically secure random names
|
|
2332
|
+
const randomId = crypto__namespace.randomBytes(16).toString('hex');
|
|
2333
|
+
const timestamp = Date.now();
|
|
2334
|
+
// Create path in secure temp directory
|
|
2335
|
+
const secureTempDir = this.getSecureTempDir();
|
|
2336
|
+
const tempPath = path__namespace.join(secureTempDir, `${prefix}-${timestamp}-${randomId}`);
|
|
2337
|
+
this.auditLog('temp_file_created', {
|
|
2338
|
+
action: 'create_temp_file',
|
|
2339
|
+
success: true,
|
|
2340
|
+
metadata: { path: this.sanitizeFilename(tempPath) }
|
|
2341
|
+
});
|
|
2342
|
+
return tempPath;
|
|
2343
|
+
}
|
|
2344
|
+
/**
|
|
2345
|
+
* Get or create secure temporary directory with restricted permissions
|
|
2346
|
+
*/
|
|
2347
|
+
getSecureTempDir() {
|
|
2348
|
+
const secureTempPath = path__namespace.join(os__namespace.tmpdir(), 'pompelmi-secure');
|
|
2349
|
+
try {
|
|
2350
|
+
const fs = require('fs');
|
|
2351
|
+
if (!fs.existsSync(secureTempPath)) {
|
|
2352
|
+
fs.mkdirSync(secureTempPath, { mode: 0o700 }); // Owner read/write/execute only
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
catch (error) {
|
|
2356
|
+
// Fallback to system temp
|
|
2357
|
+
return os__namespace.tmpdir();
|
|
2358
|
+
}
|
|
2359
|
+
return secureTempPath;
|
|
2360
|
+
}
|
|
2361
|
+
/**
|
|
2362
|
+
* Secure file cleanup with multiple overwrite passes
|
|
2363
|
+
*/
|
|
2364
|
+
async secureFileCleanup(filePath) {
|
|
2365
|
+
if (!this.config.enabled) {
|
|
2366
|
+
try {
|
|
2367
|
+
const fs = await import('fs/promises');
|
|
2368
|
+
await fs.unlink(filePath);
|
|
2369
|
+
}
|
|
2370
|
+
catch {
|
|
2371
|
+
// Ignore cleanup errors
|
|
2372
|
+
}
|
|
2373
|
+
return;
|
|
2374
|
+
}
|
|
2375
|
+
try {
|
|
2376
|
+
const fs = await import('fs/promises');
|
|
2377
|
+
const stats = await fs.stat(filePath);
|
|
2378
|
+
if (this.config.memoryProtection) {
|
|
2379
|
+
// Overwrite file with random data multiple times (DoD 5220.22-M standard)
|
|
2380
|
+
const fileSize = stats.size;
|
|
2381
|
+
const buffer = crypto__namespace.randomBytes(Math.min(fileSize, 64 * 1024)); // 64KB chunks
|
|
2382
|
+
for (let pass = 0; pass < 3; pass++) {
|
|
2383
|
+
const handle = await fs.open(filePath, 'r+');
|
|
2384
|
+
try {
|
|
2385
|
+
for (let offset = 0; offset < fileSize; offset += buffer.length) {
|
|
2386
|
+
const chunk = offset + buffer.length > fileSize
|
|
2387
|
+
? buffer.subarray(0, fileSize - offset)
|
|
2388
|
+
: buffer;
|
|
2389
|
+
await handle.write(chunk, 0, chunk.length, offset);
|
|
2390
|
+
}
|
|
2391
|
+
await handle.sync();
|
|
2392
|
+
}
|
|
2393
|
+
finally {
|
|
2394
|
+
await handle.close();
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
// Final deletion
|
|
2399
|
+
await fs.unlink(filePath);
|
|
2400
|
+
this.auditLog('temp_file_deleted', {
|
|
2401
|
+
action: 'secure_delete',
|
|
2402
|
+
success: true,
|
|
2403
|
+
metadata: {
|
|
2404
|
+
path: this.sanitizeFilename(filePath),
|
|
2405
|
+
overwritePasses: this.config.memoryProtection ? 3 : 0
|
|
2406
|
+
}
|
|
2407
|
+
});
|
|
2408
|
+
}
|
|
2409
|
+
catch (error) {
|
|
2410
|
+
this.auditLog('temp_file_deleted', {
|
|
2411
|
+
action: 'secure_delete',
|
|
2412
|
+
success: false,
|
|
2413
|
+
sanitizedError: this.sanitizeError(error),
|
|
2414
|
+
metadata: { path: this.sanitizeFilename(filePath) }
|
|
2415
|
+
});
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
/**
|
|
2419
|
+
* Calculate secure file hash for audit purposes
|
|
2420
|
+
*/
|
|
2421
|
+
calculateFileHash(data) {
|
|
2422
|
+
return crypto__namespace.createHash('sha256').update(data).digest('hex');
|
|
2423
|
+
}
|
|
2424
|
+
/**
|
|
2425
|
+
* Log audit event
|
|
2426
|
+
*/
|
|
2427
|
+
auditLog(eventType, details) {
|
|
2428
|
+
if (!this.config.enabled)
|
|
2429
|
+
return;
|
|
2430
|
+
const event = {
|
|
2431
|
+
timestamp: new Date().toISOString(),
|
|
2432
|
+
eventType,
|
|
2433
|
+
sessionId: this.sessionId,
|
|
2434
|
+
details: {
|
|
2435
|
+
action: details.action || 'unknown',
|
|
2436
|
+
success: details.success ?? true,
|
|
2437
|
+
...details
|
|
2438
|
+
}
|
|
2439
|
+
};
|
|
2440
|
+
this.auditEvents.push(event);
|
|
2441
|
+
// Write to audit log file if configured
|
|
2442
|
+
if (this.config.auditLogPath) {
|
|
2443
|
+
this.writeAuditLog(event).catch(() => {
|
|
2444
|
+
// Silent failure to prevent error loops
|
|
2445
|
+
});
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
/**
|
|
2449
|
+
* Write audit event to file
|
|
2450
|
+
*/
|
|
2451
|
+
async writeAuditLog(event) {
|
|
2452
|
+
if (!this.config.auditLogPath)
|
|
2453
|
+
return;
|
|
2454
|
+
try {
|
|
2455
|
+
const fs = await import('fs/promises');
|
|
2456
|
+
const logLine = JSON.stringify(event) + '\\n';
|
|
2457
|
+
await fs.appendFile(this.config.auditLogPath, logLine, { flag: 'a' });
|
|
2458
|
+
}
|
|
2459
|
+
catch {
|
|
2460
|
+
// Silent failure
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
/**
|
|
2464
|
+
* Generate cryptographically secure session ID
|
|
2465
|
+
*/
|
|
2466
|
+
generateSessionId() {
|
|
2467
|
+
return crypto__namespace.randomBytes(16).toString('hex');
|
|
2468
|
+
}
|
|
2469
|
+
/**
|
|
2470
|
+
* Get current audit events for this session
|
|
2471
|
+
*/
|
|
2472
|
+
getAuditEvents() {
|
|
2473
|
+
return [...this.auditEvents];
|
|
2474
|
+
}
|
|
2475
|
+
/**
|
|
2476
|
+
* Clear sensitive data from memory
|
|
2477
|
+
*/
|
|
2478
|
+
clearSensitiveData() {
|
|
2479
|
+
if (!this.config.enabled || !this.config.memoryProtection)
|
|
2480
|
+
return;
|
|
2481
|
+
// Clear audit events
|
|
2482
|
+
this.auditEvents.length = 0;
|
|
2483
|
+
// Force garbage collection if available
|
|
2484
|
+
if (global.gc) {
|
|
2485
|
+
global.gc();
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
/**
|
|
2489
|
+
* Validate transport security
|
|
2490
|
+
*/
|
|
2491
|
+
validateTransportSecurity(url) {
|
|
2492
|
+
if (!this.config.enabled || !this.config.requireSecureTransport) {
|
|
2493
|
+
return true;
|
|
2494
|
+
}
|
|
2495
|
+
if (!url)
|
|
2496
|
+
return true;
|
|
2497
|
+
try {
|
|
2498
|
+
const urlObj = new URL(url);
|
|
2499
|
+
const isSecure = urlObj.protocol === 'https:' || urlObj.hostname === 'localhost' || urlObj.hostname === '127.0.0.1';
|
|
2500
|
+
if (!isSecure) {
|
|
2501
|
+
this.auditLog('security_violation', {
|
|
2502
|
+
action: 'insecure_transport',
|
|
2503
|
+
success: false,
|
|
2504
|
+
metadata: { protocol: urlObj.protocol, hostname: urlObj.hostname }
|
|
2505
|
+
});
|
|
2506
|
+
}
|
|
2507
|
+
return isSecure;
|
|
2508
|
+
}
|
|
2509
|
+
catch {
|
|
2510
|
+
return false;
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
// Global HIPAA compliance instance
|
|
2515
|
+
let hipaaManager = null;
|
|
2516
|
+
/**
|
|
2517
|
+
* Initialize HIPAA compliance
|
|
2518
|
+
*/
|
|
2519
|
+
function initializeHipaaCompliance(config) {
|
|
2520
|
+
hipaaManager = new HipaaComplianceManager(config);
|
|
2521
|
+
return hipaaManager;
|
|
2522
|
+
}
|
|
2523
|
+
/**
|
|
2524
|
+
* Get current HIPAA compliance manager
|
|
2525
|
+
*/
|
|
2526
|
+
function getHipaaManager() {
|
|
2527
|
+
return hipaaManager;
|
|
2528
|
+
}
|
|
2529
|
+
/**
|
|
2530
|
+
* HIPAA-compliant error wrapper
|
|
2531
|
+
*/
|
|
2532
|
+
function createHipaaError(error, context) {
|
|
2533
|
+
const manager = getHipaaManager();
|
|
2534
|
+
if (!manager) {
|
|
2535
|
+
return typeof error === 'string' ? new Error(error) : error;
|
|
2536
|
+
}
|
|
2537
|
+
const sanitizedMessage = manager.sanitizeError(error);
|
|
2538
|
+
const hipaaError = new Error(sanitizedMessage);
|
|
2539
|
+
manager.auditLog('error_occurred', {
|
|
2540
|
+
action: context || 'error',
|
|
2541
|
+
success: false,
|
|
2542
|
+
sanitizedError: sanitizedMessage
|
|
2543
|
+
});
|
|
2544
|
+
return hipaaError;
|
|
2545
|
+
}
|
|
2546
|
+
/**
|
|
2547
|
+
* HIPAA-compliant temporary file utilities
|
|
2548
|
+
*/
|
|
2549
|
+
const HipaaTemp = {
|
|
2550
|
+
createPath: (prefix) => {
|
|
2551
|
+
const manager = getHipaaManager();
|
|
2552
|
+
return manager ? manager.createSecureTempPath(prefix) : path__namespace.join(os__namespace.tmpdir(), `${prefix || 'pompelmi'}-${Date.now()}`);
|
|
2553
|
+
},
|
|
2554
|
+
cleanup: async (filePath) => {
|
|
2555
|
+
const manager = getHipaaManager();
|
|
2556
|
+
if (manager) {
|
|
2557
|
+
await manager.secureFileCleanup(filePath);
|
|
2558
|
+
}
|
|
2559
|
+
else {
|
|
2560
|
+
try {
|
|
2561
|
+
const fs = await import('fs/promises');
|
|
2562
|
+
await fs.unlink(filePath);
|
|
2563
|
+
}
|
|
2564
|
+
catch {
|
|
2565
|
+
// Ignore errors
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
};
|
|
2570
|
+
|
|
2113
2571
|
function mapMatchesToVerdict(matches = []) {
|
|
2114
2572
|
if (!matches.length)
|
|
2115
2573
|
return 'clean';
|
|
@@ -2326,10 +2784,17 @@ function definePolicy(input = {}) {
|
|
|
2326
2784
|
|
|
2327
2785
|
exports.CommonHeuristicsScanner = CommonHeuristicsScanner;
|
|
2328
2786
|
exports.DEFAULT_POLICY = DEFAULT_POLICY;
|
|
2787
|
+
exports.HipaaComplianceManager = HipaaComplianceManager;
|
|
2788
|
+
exports.HipaaTemp = HipaaTemp;
|
|
2789
|
+
exports.PRESET_CONFIGS = PRESET_CONFIGS;
|
|
2790
|
+
exports.SUSPICIOUS_PATTERNS = SUSPICIOUS_PATTERNS;
|
|
2329
2791
|
exports.composeScanners = composeScanners;
|
|
2792
|
+
exports.createHipaaError = createHipaaError;
|
|
2330
2793
|
exports.createPresetScanner = createPresetScanner;
|
|
2331
2794
|
exports.createZipBombGuard = createZipBombGuard;
|
|
2332
2795
|
exports.definePolicy = definePolicy;
|
|
2796
|
+
exports.getHipaaManager = getHipaaManager;
|
|
2797
|
+
exports.initializeHipaaCompliance = initializeHipaaCompliance;
|
|
2333
2798
|
exports.mapMatchesToVerdict = mapMatchesToVerdict;
|
|
2334
2799
|
exports.scanBytes = scanBytes;
|
|
2335
2800
|
exports.scanFile = scanFile;
|