MEDIUM: Credentials and access keys stored in plaintext in JSON database — no encryption at rest #12

Closed
opened 2026-05-09 00:02:58 +00:00 by Mark · 1 comment
Owner

Severity: Medium

Location

backend/src/database.ts, backend/data/ directory

Description

The database stores all user credentials (login names, recovery emails, access keys) as plaintext in JSON files:

// credentials stored directly in JSON without encryption
credentials: {
  loginName: 'user@example.com',
  recoveryEmail: 'backup@example.com',
  accessKeys: [
    { id: 'ak1', name: 'API Key', key: 'sk-...' }
  ],
  twoFactorEnabled: true,
}

The data files are in backend/data/ which is gitignored but still on disk.

Impact

  • Anyone with filesystem access to the server can read all stored credentials
  • No encryption at rest means data exposure if the disk is compromised
  • The README claims this is a 'secure' vault, which is misleading

Suggested Fix

  1. Encrypt sensitive fields before writing to disk (e.g., using crypto.createCipheriv with a derived key from the JWT secret or a separate encryption key)
  2. Or use a proper encrypted database (SQLite with encryption extension, etc.)
  3. At minimum, document that credentials are not encrypted at rest
## Severity: Medium ## Location `backend/src/database.ts`, `backend/data/` directory ## Description The database stores all user credentials (login names, recovery emails, access keys) as plaintext in JSON files: ```typescript // credentials stored directly in JSON without encryption credentials: { loginName: 'user@example.com', recoveryEmail: 'backup@example.com', accessKeys: [ { id: 'ak1', name: 'API Key', key: 'sk-...' } ], twoFactorEnabled: true, } ``` The data files are in `backend/data/` which is gitignored but still on disk. ## Impact - Anyone with filesystem access to the server can read all stored credentials - No encryption at rest means data exposure if the disk is compromised - The README claims this is a 'secure' vault, which is misleading ## Suggested Fix 1. Encrypt sensitive fields before writing to disk (e.g., using `crypto.createCipheriv` with a derived key from the JWT secret or a separate encryption key) 2. Or use a proper encrypted database (SQLite with encryption extension, etc.) 3. At minimum, document that credentials are not encrypted at rest
Author
Owner

Fixed in commit. Closing.

Fixed in commit. Closing.
Mark closed this issue 2026-05-21 00:59:47 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Mark/subvault#12
No description provided.