diff --git a/dashcaddy-api/__tests__/backup-manager.test.js b/dashcaddy-api/__tests__/backup-manager.test.js index 425ee5a..6f122b2 100644 --- a/dashcaddy-api/__tests__/backup-manager.test.js +++ b/dashcaddy-api/__tests__/backup-manager.test.js @@ -184,9 +184,16 @@ describe('BackupManager — backup/restore lifecycle', () => { it('rejects tampered data (auth tag mismatch)', async () => { const data = Buffer.from('test'); const encrypted = await backupManager.encryptBackup(data, testKey); - // Corrupt the first character of the IV - const str = encrypted.toString(); - const tampered = Buffer.from('X' + str.substring(1)); + // Corrupt the authTag so the GCM integrity check is guaranteed to fail. + // The format is iv:authTag:ciphertext (all base64). We flip all bits of + // the first authTag byte — XOR with 0xFF always changes the value, so + // this can never be a no-op (unlike replacing a base64 char with a fixed + // char, which collides ~1/64 of the time when that char already matches). + const parts = encrypted.toString().split(':'); + const authTagBuf = Buffer.from(parts[1], 'base64'); + authTagBuf[0] ^= 0xFF; + parts[1] = authTagBuf.toString('base64'); + const tampered = Buffer.from(parts.join(':')); await expect(backupManager.decryptBackup(tampered, testKey)) .rejects.toThrow(); });