Harden ~/.flowise/encryption.key file permissions to 0o600#6420
Conversation
There was a problem hiding this comment.
Code Review
This pull request enhances security by setting restrictive file permissions (0o600) when writing the encryption key to disk. The review feedback suggests further hardening the implementation by ensuring the parent directory exists before writing and explicitly applying permissions via chmod to handle cases where the file already exists, as the mode option in writeFile only applies to new file creation.
| ? path.join(process.env.SECRETKEY_PATH, 'encryption.key') | ||
| : path.join(getUserHome(), '.flowise', 'encryption.key') | ||
| await fs.promises.writeFile(defaultLocation, encryptKey) | ||
| await fs.promises.writeFile(defaultLocation, encryptKey, { mode: 0o600 }) |
There was a problem hiding this comment.
While adding { mode: 0o600 } is a good security practice, there are two additional improvements for robustness and complete hardening:
- Directory Creation:
fs.promises.writeFilewill throw an error if the parent directory (e.g.,~/.flowise) does not exist. This is likely to happen on fresh installations. Usingfs.promises.mkdirwith{ recursive: true }ensures the directory exists before writing. - Existing Files: The
modeoption inwriteFileonly applies when a new file is created. If the file already exists (e.g., if it was corrupted or empty, causing the initialreadFileto fail), its permissions will not be updated. Adding an explicitfs.promises.chmodcall ensures the file is hardened regardless of whether it was created or overwritten.
Additionally, consider applying similar hardening to other sensitive files, such as those handled in getOrCreateStoredSecret (line 1735).
await fs.promises.mkdir(path.dirname(defaultLocation), { recursive: true })
await fs.promises.writeFile(defaultLocation, encryptKey, { mode: 0o600 })
await fs.promises.chmod(defaultLocation, 0o600)
What
Pass
{ mode: 0o600 }tofs.promises.writeFilewhen persisting~/.flowise/encryption.key, so the master encryption key is created with owner-only-read permissions (-rw-------) instead of the umask-default0o644(-rw-r--r--).Why
The encryption key wraps every credential stored in the Flowise database. On a stock Linux / macOS install (umask
022), the key file currently lands at0o644— readable by any other UID on the host. On multi-user systems (shared CI runners, multi-tenant servers, containers that mount the host's~/.flowise), that's a credential-store exposure.Node's
fs.promises.writeFiledoes not chmod by default — passingmodeis the standard way to set the on-creation permission. The same pattern is used across the Node ecosystem for secret files (e.g., npm's~/.npmrconce it contains a token, GitHub CLI's hosts.yml, etc.).This is a one-line defensive change with no API or behavioral impact: existing keys are not touched, only newly-created keys get the tighter mode.
How to verify
Before this PR:
-rw-r--r--. After this PR:-rw-------.