Summary
Three separate TOCTOU (Time-of-Check-to-Time-of-Use) race conditions found across the codebase:
1. JSON File Save (dist/json-file-Dl3Z1jL1.js:13-21)
saveJsonFile does existsSync(dir) → mkdirSync → writeFileSync without atomic write. Two concurrent processes can produce corrupt/partial JSON. loadJsonFile can read a partially-written file.
2. Matrix Credentials Migration (dist/credentials-read-BLFr7diG.js:47-55)
loadMatrixCredentials checks existsSync(credPath) → existsSync(legacyPath) → parseMatrixCredentialsFile(legacyPath) → renameSync. If another process migrated between check and read, unhandled ENOENT is thrown.
3. GCP Credentials Loading (dist/anthropic-vertex-provider-B2x4YywE.js:39-47)
existsSync(credentialsPath) check followed by readFileSync(credentialsPath) in a separate function. Between check and read, the file could be replaced with a symlink.
Impact
- Config corruption on concurrent access, potentially causing service failure
- Crash on concurrent startup during Matrix credential migration
- Symlink substitution in GCP credentials could redirect API traffic
Suggested Fix
- JSON save: Implement atomic write (write to temp +
rename())
- Matrix: Wrap
parseMatrixCredentialsFile in try/catch for ENOENT
- GCP: Use
readFile() directly with error handling, skip the existsSync check
Summary
Three separate TOCTOU (Time-of-Check-to-Time-of-Use) race conditions found across the codebase:
1. JSON File Save (
dist/json-file-Dl3Z1jL1.js:13-21)saveJsonFiledoesexistsSync(dir)→mkdirSync→writeFileSyncwithout atomic write. Two concurrent processes can produce corrupt/partial JSON.loadJsonFilecan read a partially-written file.2. Matrix Credentials Migration (
dist/credentials-read-BLFr7diG.js:47-55)loadMatrixCredentialschecksexistsSync(credPath)→existsSync(legacyPath)→parseMatrixCredentialsFile(legacyPath)→renameSync. If another process migrated between check and read, unhandledENOENTis thrown.3. GCP Credentials Loading (
dist/anthropic-vertex-provider-B2x4YywE.js:39-47)existsSync(credentialsPath)check followed byreadFileSync(credentialsPath)in a separate function. Between check and read, the file could be replaced with a symlink.Impact
Suggested Fix
rename())parseMatrixCredentialsFilein try/catch for ENOENTreadFile()directly with error handling, skip theexistsSynccheck