T09 · Insecure Skill Coding Practices
Warning
- Location
- src/restore.js:81
- Finding
- Archive Contents Are Extracted Before AES-GCM Authentication Completes<![CDATA[ ## Vulnerability Details **File Location**: `src/restore.js:81-103` **Vulnerability Type**: Authenticated decryption performed after filesystem modification **Risk Level**: Medium ### Vulnerable Code ```js splitter.on('tag', (tag) => { try { decipher.setAuthTag(tag); } catch (e) { reject(new Error('Invalid auth tag')); } }); const extractor = tar.x({ cwd: targetDir, 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-GCM provides authenticity only after the complete ciphertext has been processed and the authentication tag has been verified. However, the implementation streams plaintext emitted by `decipher` directly into `tar.x()`. The TAR extractor can therefore create or overwrite files in `targetDir` before AES-GCM authentication finishes. If the supplied archive is corrupted, truncated, encrypted under a different password, or deliberately modified, the decipher may emit unauthenticated plaintext before eventually reporting an authentication failure. Rejecting the Promise does not roll back filesystem changes already made by the extractor. Consequently, an unsuccessful import can still leave the destination in a partially modified state. ### Attack Path 1. An attacker obtains or produces a modified `.oca` archive and supplies it to the victim as a migration backup. 2. The victim invokes `migrator import` with the archive. 3. The program begins decrypting the ciphertext and immediately streams produced plaintext to the TAR extractor. 4. The extractor creates or overwrites files under the selected destination before the final GCM tag is validated. 5. Final authentication fails and ...[truncated 972 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not stream unauthenticated plaintext directly into the final destination. 2. Decrypt the archive into a securely created temporary file first. 3. Wait for the decipher stream to complete successfully, including final GCM authentication, before passing the resulting TAR archive to `tar.x()`. 4. Extract the authenticated archive into a separate temporary directory rather than directly into the destination. 5. Validate extracted entries and expected archive structure before installation. 6. Move validated files into the final destination only after both authentication and extraction succeed. Use atomic rename operations where possible. 7. Remove all temporary files and directories on authentication, extraction, or installation failure. 8. Consider creating a backup of files that will be replaced so a failed installation phase can be rolled back. 9. Bind the unencrypted archive header to the ciphertext using AES-GCM additional authenticated data, or include equivalent validated metadata inside the encrypted content. A safer sequence is: ```text Encrypted archive -> secure temporary encrypted/decrypted storage -> complete AES-GCM tag verification -> temporary extraction directory -> archive structure validation -> atomic installation into destination ``` ]]>
