T09 · Insecure Skill Coding Practices
- Location
src/restore.js:75- Finding
Archive contents are extracted before AES-GCM authentication succeeds
- Content
View full analysis
{ const input = fs.createReadStream(archivePath); try { const { salt, iv } = await readHeader(input); const key = crypto.scryptSync(password, salt, 32); const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv); const splitter = new GcmTagSplitter(); splitter.on('tag', (tag) => { try { decipher.setAuthTag(tag); } catch (e) { reject(new Error('Invalid auth tag')); } }); const extractor = tar.x({ cwd: targetDir, filter: (path) => { // Security: Block absolute paths and parent directory traversal const normalizedPath = path.replace(/\\/g, '/'); if (normalizedPath.startsWith('/') || normalizedPath.includes('..')) { console.warn(`🚨 Security: Blocked suspicious path in archive: ${path}`); return false; } return true; }, onentry: (entry) => { console.log(`Extracting: ${entry.path}`); } }); decipher.on('error', () => reject(new Error('Decryption failed (Wrong password or corrupted archive)'))); extractor.on('error', reject); extractor.on('end', () => { console.log('🔓 Decryption & Extraction complete.'); resolve(); }); input.pipe(splitter).pipe(decipher).pipe(extractor); ``` ### Technical Analysis AES-256-GCM provides confidentiality and integrity only after the authentication tag has been supplied and successfully verified. Node.js can emit plaintext through a GCM decipher before `decipher.final()` verifies that tag. Here, decrypted bytes are strea ...[truncated 2095 chars]- Remediation
View remediation
