Summary
OAuth access tokens and refresh tokens are stored in plaintext JSON on disk, creating a significant security risk if the user's machine is compromised.
Severity
HIGH
Affected Files
src/services/x-auth.ts (Line 191)
Code Snippet
writeFileSync(this.tokensPath, JSON.stringify(store, null, 2), { mode: 0o600 });
Security Risk
While file permissions are correctly set to 0o600, tokens are stored unencrypted:
- If the machine is compromised, tokens are immediately accessible
- Tokens may be backed up or synced to cloud storage
- No encryption-at-rest protection
- Stored at
.shippost-tokens.json in predictable location
Potential Impact
- Complete Twitter/X account compromise if tokens are stolen
- Ability to post, read, and modify content as the user
- Long-lived access if refresh token is stolen
Recommended Fix
Implement encryption for tokens at rest:
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'crypto';
class SecureTokenStorage {
private getEncryptionKey(): Buffer {
// Use machine-specific key derivation
const machineId = getMachineId(); // Use a machine fingerprint
return scryptSync(machineId, 'shippost-salt', 32);
}
encryptTokens(tokens: XTokens): string {
const key = this.getEncryptionKey();
const iv = randomBytes(16);
const cipher = createCipheriv('aes-256-gcm', key, iv);
const encrypted = Buffer.concat([
cipher.update(JSON.stringify(tokens), 'utf8'),
cipher.final()
]);
const authTag = cipher.getAuthTag();
return Buffer.concat([iv, authTag, encrypted]).toString('base64');
}
decryptTokens(encrypted: string): XTokens {
const key = this.getEncryptionKey();
const data = Buffer.from(encrypted, 'base64');
const iv = data.subarray(0, 16);
const authTag = data.subarray(16, 32);
const ciphertext = data.subarray(32);
const decipher = createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(authTag);
const decrypted = Buffer.concat([
decipher.update(ciphertext),
decipher.final()
]);
return JSON.parse(decrypted.toString('utf8'));
}
}
Labels
security, vulnerability, authentication
Summary
OAuth access tokens and refresh tokens are stored in plaintext JSON on disk, creating a significant security risk if the user's machine is compromised.
Severity
HIGH
Affected Files
src/services/x-auth.ts(Line 191)Code Snippet
Security Risk
While file permissions are correctly set to
0o600, tokens are stored unencrypted:.shippost-tokens.jsonin predictable locationPotential Impact
Recommended Fix
Implement encryption for tokens at rest:
Labels
security, vulnerability, authentication