fix: set file permissions on AWS credentials, remove sensitive data from SSH logs#1873
fix: set file permissions on AWS credentials, remove sensitive data from SSH logs#1873jlima8900 wants to merge 2 commits intoKeeper-Security:releasefrom
Conversation
| shutil.copy2(creds_filename, backup_file) | ||
| with open(creds_filename, 'w') as f: | ||
| cp.write(f) | ||
| os.chmod(creds_filename, 0o600) |
There was a problem hiding this comment.
One concern — race condition (TOCTOU): The file is opened, written, closed, and then chmod'd. There is a brief window where the file exists at 0644 (or whatever the process umask dictates) before permissions are restricted. On a paranoid multi-user system, the correct fix would be to either:
Set a restrictive umask before open() and restore it afterward,
or
Open the file descriptor with os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) and wrap it with open(fd, 'w').
8e71c18 to
02e8131
Compare
|
Good catch on the TOCTOU window. You're right — there's a brief moment where the file exists with default umask permissions before I'll update to use fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
with open(fd, 'w') as f:
f.write(content)This way the file is created with 0600 from the start — no window for another process to read it. |
…on narrowing AWS credentials (aws_accesskey.py): - Eliminate TOCTOU race: use os.open() with 0o600 mode instead of open() + chmod() so file is never world-readable - Create backup with same atomic permission pattern - Use os.fdopen + fchmod to harden existing files SSH logs (ssh.py): - Sanitize debug output: log byte counts instead of raw content to prevent credential leakage in log files PAM base (base.py): - Narrow all json.loads catches to json.JSONDecodeError only (drop unreachable ValueError, TypeError, KeyError) - Add structured error details (e.msg, e.lineno, e.colno) to logs - Split import_schedule_field handler into separate JSONDecodeError vs (ValueError, KeyError) blocks Tests: - 19 tests covering file permissions, log sanitization, exception narrowing, and TOCTOU atomicity - Skip botocore-dependent tests when botocore not installed
82d99f3 to
f1cbf64
Compare
…patterns - SEC-1/2: Rewrite set_file_permissions and ensure_config_permissions to use O_NOFOLLOW + fstat + fchmod (fd-based) instead of islink + stat + chmod to prevent symlink swap between check and chmod - SEC-4: Apply sanitize_debug_data() in debug_decorator so credentials passed as function args/return values are redacted in DEBUG logs - SEC-7: Add Commander-specific secret patterns (private_pem_key, device_token, access_token, gateway_token, session_token, data_key) - ERR-1: Narrow except Exception to (OSError, SubprocessError) in set_file_permissions - BUG-2: Fix ensure_config_permissions to warn only when permissions are more permissive than 0o600 (was treating 0o400 as insecure)
Summary
Two validated findings from a security audit of the Commander codebase (445 Python files, 10 categories, 3-pass validation).
KC-2026-001: AWS credentials file permissions
The
awskeyplugin writes rotated AWS credentials without setting restrictive file permissions. If the credentials file is newly created (custom path), it inherits umask defaults (typically0644), making the AWS secret access key readable by other users on multi-user systems.File:
keepercommander/plugins/awskey/aws_accesskey.py:138Fix: Add
os.chmod(creds_filename, 0o600)after writing credentials file and backup.KC-2026-002: SSH plugin logs password command output
The SSH password rotation plugin logs raw terminal output from the
passwdcommand at DEBUG level. This output can include echoed password characters, credential-related prompts, or error messages that reveal password context.File:
keepercommander/plugins/ssh/ssh.py:118,126,131,138Fix: Replace raw output logging with response size only (
'Rotation command responded (%d bytes)'). The actual credential values are no longer included in log statements.Audit methodology
Test plan
0600permissions after rotation0600permissions