T09 · Insecure Skill Coding Practices
Warning
- Location
- memory/wal.js:78
- Finding
- WAL checksum verification always accepts modified entries<![CDATA[ ## Vulnerability Details **File Location**: `memory/wal.js:78-83` **Vulnerability Type**: Broken integrity verification **Risk Level**: Medium ### Vulnerable Code ```javascript verifyChecksum() { if (!this.checksum) return true; const expected = this.calculateChecksum(); return this.checksum === expected; } ``` ### Technical Analysis `verifyChecksum()` invokes `calculateChecksum()`, which calculates a new checksum and assigns it directly to `this.checksum`. The subsequent comparison therefore compares the newly calculated value with itself rather than comparing it with the checksum originally read from disk. Entries with no checksum are also accepted because the method immediately returns `true` when `this.checksum` is absent. As a result, an attacker who can modify a WAL file can alter its transaction ID, event data, metadata, sequence, or timestamp without the modification being detected by `readAllEntries()`. This is not a cryptographic authenticity control and does not protect recovery data against malicious local modification. ### Attack Path 1. The attacker obtains write access to the configured WAL directory, such as through the same operating-system account, an overly permissive directory, or another compromised local process. 2. The attacker edits a `wal-*.log` entry and changes its transaction metadata or event data. 3. The attacker supplies an arbitrary checksum or removes the checksum. 4. `readAllEntries()` parses the modified entry and calls `verifyChecksum()`. 5. Verification recalculates and overwrites the stored checksum, or accepts the missing checksum. 6. `recover()` processes the modified entry as valid recovery state. ### Impact Assessment Successful exploitation can compromise the integrity of persisted task and transaction state. An attacker may falsify transaction completion, alter recovered metadata, hide corruption, or cause the application to recover misleading state. Exploitation requires local write access t ...[truncated 218 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Preserve the checksum loaded from disk in a separate variable before calculating the expected value. - Make checksum calculation a pure function that does not mutate the entry. - Reject missing checksums whenever `enableChecksum` is enabled. - Use a timing-safe comparison for cryptographic authentication values. - If protection from malicious modification is required, replace the current non-cryptographic hash with HMAC-SHA-256 using a protected key. - Validate entry types, sequence values, transaction identifiers, timestamps, and data schemas before recovery. - Add tests proving that changes to every protected field cause verification to fail. Example: ```javascript calculateChecksumValue() { const content = JSON.stringify({ type: this.type, transactionId: this.transactionId, data: this.data, sequence: this.sequence, timestamp: this.timestamp, }); return createHash('sha256').update(content).digest('hex'); } verifyChecksum() { if (!this.checksum) return false; const stored = this.checksum; const expected = this.calculateChecksumValue(); return stored === expected; } ``` For authenticity rather than accidental-corruption detection, use an HMAC instead of an unkeyed hash. ]]>
