fix(security): Clear-text storage of sensitive information#1004
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request addresses a security vulnerability (issue #938) related to clear-text storage of sensitive information in .env files. Instead of removing secrets from the .env file (as suggested in PR #937), this PR takes the approach of hardening file permissions to restrict access to the file owner only.
Changes:
- Replaces standard
open()calls withos.open()using mode 0o600 for all .env file writes to ensure owner-only read/write permissions - Adds
flush()andfsync()calls to guarantee data durability when writing configuration files - Elevates OPENRAG_VERSION update error logging from debug to error level for better visibility
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@rodageve Looking forward to your thoughts on it too? BE side with the edge case migrations I am all good, looping you in for the Cloud scenario. |
Issues - #938 Summary Hardens .env file handling in EnvManager to prevent cleartext secrets from being exposed via insecure file permissions. All .env file writes now use os.open with 0o600 mode to restrict access to the file owner only, and adds fsync to ensure data durability. Also removes trailing whitespace throughout the file. Security Hardening - Replace `open()` with `os.open(..., 0o600)` + `os.fdopen()` for all .env file writes, ensuring owner-only (read/write) permissions on creation - Add `os.chmod(self.env_file, 0o600)` when overwriting pre-existing .env files to retroactively restrict permissions - Add `f.flush()` + `os.fsync()` calls to the main `save_env_file()` write path to guarantee data is durably written to disk Logging Improvements - Elevate `OPENRAG_VERSION` update error from `logger.debug` to `logger.error` so failures surface in standard log output Code Cleanup - Remove redundant `import os` statement in `ensure_version_in_env()` (already imported at module level) - Strip trailing whitespace on blank lines throughout the file
Issues - #938 Summary Two code paths in EnvManager left .env files with uncontrolled permissions after writing them. This commit adds the missing chmod calls so that every path — legacy migration, backup creation, and new-file creation — always results in owner-only (0o600) access, preventing cleartext secret exposure to other OS users. A new unit test target is also added to the Makefile for faster feedback on unit-only test runs. Security Fixes - Apply os.chmod(0o600) to the migrated .env after shutil.copy2 in the legacy migration branch (__init__), which previously inherited the source file's permissions. - Apply os.chmod(0o600) to the timestamped backup file created in save_env_file before the new .env is written, ensuring the backup is also protected. Tests - Add tests/unit/test_env_manager.py with 168 lines of unit tests covering all three affected code paths: - TestSaveEnvFilePermissions: new file creation, overwrite of a permissive existing file, and backup file permissions. - TestEnsureOpenragVersionPermissions: update of an existing permissive file and creation of a new file. - TestLegacyMigrationPermissions: migrated file receives 0o600 after copy. - All tests use pytest tmp_path and unittest.mock; no running infrastructure required. Tests are skipped on Windows (Unix permission model only). Build / Developer Experience - Add test-unit Makefile target (uv run pytest tests/unit/ -v) for running unit tests in isolation without triggering integration tests. - Register test-unit in .PHONY and add it to the help_test output.
84dfb39 to
e1e4234
Compare
Status Update
|
Integration Test Failures
|
Status Update
|
Applying 0600 file permissions to .env is a good practice but provides a low level of overall security in the context of a kubernetes environment. This is probably the minimum we should do and does provide some level of security. |
|
@mpawlow can you try the integration test in this PR? |
|
Issues
Summary
Hardens .env file handling in EnvManager to prevent cleartext secrets from being exposed via insecure file permissions. All .env file writes now use os.open with 0o600 mode to restrict access to the file owner only, and adds fsync to ensure data durability. Also removes trailing whitespace throughout the file.
Security Hardening
open()withos.open(..., 0o600)+os.fdopen()for all .env file writes, ensuring owner-only (read/write) permissions on creationos.chmod(self.env_file, 0o600)when overwriting pre-existing .env files to retroactively restrict permissionsf.flush()+os.fsync()calls to the mainsave_env_file()write path to guarantee data is durably written to disklegacy migration branch (init), which previously inherited the
source file's permissions.
save_env_file before the new .env is written, ensuring the backup is
also protected.
Logging Improvements
OPENRAG_VERSIONupdate error fromlogger.debugtologger.errorso failures surface in standard log outputCode Cleanup
import osstatement inensure_version_in_env()(already imported at module level)Tests
all three affected code paths:
existing file, and backup file permissions.
file and creation of a new file.
required. Tests are skipped on Windows (Unix permission model only).
Build / Developer Experience
unit tests in isolation without triggering integration tests.
Full Background Info on Remediation
Related PRs
Test Coverage
Test 1 — save_env_file: new file creation
Test 2 — save_env_file: new .env when prior file exists (permissions)
Test 3 — save_env_file: backup file permissions
Test 4 — ensure_openrag_version: existing file update path
Test 5 — ensure_openrag_version: new file creation path
Test 6 — Legacy migration path in init
6 tests across 3 classes: