Skip to content

fix: restrict file permissions on auth, config, and log files to prevent local credential theft#244

Merged
aviatco merged 13 commits into
microsoft:mainfrom
iemejia:fix/restrict-file-permissions-sensitive-data
Jun 18, 2026
Merged

fix: restrict file permissions on auth, config, and log files to prevent local credential theft#244
aviatco merged 13 commits into
microsoft:mainfrom
iemejia:fix/restrict-file-permissions-sensitive-data

Conversation

@iemejia

@iemejia iemejia commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Auth files (auth.json, config.json, context-{pid}.json) and debug log directories were created with default OS permissions (0o644 for files, 0o755 for directories), making them world-readable on multi-user Linux/macOS systems. This exposed MSAL token caches, auth metadata, and debug logs containing sensitive API responses to other local users.

Security Impact

File Data at Risk Old Permissions New Permissions
~/.config/fab/ Container for all auth/config 0o755 (world-traversable) 0o700 (owner-only)
~/.config/fab/auth.json Tenant ID, SPN client ID, identity type 0o644 (world-readable) 0o600 (owner-only)
~/.config/fab/config.json Azure subscription IDs, capacity settings 0o644 (world-readable) 0o600 (owner-only)
~/.config/fab/context-{pid}.json Navigation state (workspace/item names) 0o644 (world-readable) 0o600 (owner-only)
Log directory Parent of debug log with HTTP traffic 0o755 (world-traversable) 0o700 (owner-only)

CWE-276: Incorrect Default Permissions

Changes

  • fab_auth.py: Write auth.json with 0o600 via os.open() instead of open()
  • fab_state_config.py: Create ~/.config/fab/ with mode=0o700; write config.json with 0o600 via os.open() with a new _write_restricted_file() helper
  • fab_logger.py: Create log directory with mode=0o700
  • fab_context.py: Write context-{pid}.json with 0o600 via os.open()

Cross-Platform Behavior

  • Linux/macOS: Fixes enforce 0o600/0o700 correctly — resolves the vulnerability
  • Windows: The mode parameter is a no-op (Windows uses ACLs, not POSIX permissions). Default Windows ACLs on user profile directories already restrict access to the owner, so the original behavior was not vulnerable there. These changes are safely a no-op on Windows.

Tests

6 new tests verifying:

  • Config directory created with 0o700
  • config.json written with 0o600 (initial write and overwrite)
  • auth.json written with 0o600 (initial write and overwrite)
  • Log directory created with 0o700

All existing tests pass (488 total).

…ent local credential theft

Auth files (auth.json, config.json) and debug log directories were created
with default OS permissions (0o644/0o755), making them world-readable on
multi-user systems. This exposed MSAL token caches, auth metadata, and
debug logs containing sensitive API responses to other local users.

Changes:
- fab_auth.py: Write auth.json with 0o600 via os.open() instead of open()
- fab_state_config.py: Create ~/.config/fab/ with mode 0o700; write
  config.json with 0o600 via os.open() instead of open()
- fab_logger.py: Create log directory with mode 0o700
- fab_context.py: Write context-{pid}.json with 0o600 via os.open()

Note: On Windows the mode parameter is a no-op (Windows uses ACLs, not
POSIX permissions). Default Windows ACLs on user profile directories
already restrict access to the owner, so the original behavior was not
vulnerable there.

CWE-276: Incorrect Default Permissions
Copilot AI review requested due to automatic review settings June 7, 2026 12:23
@iemejia iemejia requested a review from a team as a code owner June 7, 2026 12:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR tightens filesystem permissions for Fabric CLI’s config/auth/context/log artifacts and adds test coverage to validate that newly created directories/files are owner-restricted.

Changes:

  • Restrict created directories to 0o700 (config + log directories).
  • Restrict created files to 0o600 by switching writes to os.open(..., mode=0o600) + os.fdopen.
  • Add tests asserting restricted permissions for config/auth/log paths and overwrites.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/fabric_cli/core/fab_state_config.py Create config dir with 0o700; write config via restricted file helper.
src/fabric_cli/core/fab_logger.py Create log directory with 0o700.
src/fabric_cli/core/fab_context.py Save context file using restricted 0o600 open.
src/fabric_cli/core/fab_auth.py Save auth file using restricted 0o600 open.
tests/test_core/test_fab_state_config.py Add permission tests for config dir + config file.
tests/test_core/test_fab_logger.py Add permission test for log directory creation.
tests/test_core/test_fab_auth.py Add permission tests for auth.json creation + overwrite.

Comment thread src/fabric_cli/core/fab_state_config.py Outdated
Comment thread src/fabric_cli/core/fab_state_config.py Outdated
Comment thread src/fabric_cli/core/fab_auth.py Outdated
Comment thread src/fabric_cli/core/fab_context.py Outdated
Comment thread src/fabric_cli/core/fab_state_config.py
Comment thread tests/test_core/test_fab_state_config.py Outdated
iemejia added 2 commits June 7, 2026 14:26
…s, TOCTOU fix, Windows test skip

- Guard os.fdopen failures with try/except to close fd on error
- Add os.chmod() after writes to tighten permissions on pre-existing files
- Fix TOCTOU race in config_location() with exist_ok=True
- Centralize _write_restricted_file() and reuse in auth/context modules
- Skip POSIX permission assertions on Windows (os.name == 'nt')
- Rewrite config_location test to exercise real function via expanduser patch
- Add tests for tightening permissions on pre-existing permissive files
- Update context persistence tests for _write_restricted_file usage
Copilot AI review requested due to automatic review settings June 7, 2026 12:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Comment thread src/fabric_cli/core/fab_logger.py
Comment thread src/fabric_cli/core/fab_state_config.py Outdated
Comment thread .changes/unreleased/fixed-20260607-134043.yaml
Comment thread tests/test_core/test_fab_state_config.py Outdated
Comment thread tests/test_core/test_fab_state_config.py Outdated
…ure, test cleanup

- Add _chmod_if_posix() to fab_logger.py to tighten pre-existing log
  directories (mirrors config_location behavior)
- Emit warning via logging.warning when chmod fails on POSIX instead
  of silently swallowing the error
- Fix changelog text to accurately describe scope (directories + files)
- Remove unused sys import and config_dir variable in tests
Comment thread src/fabric_cli/core/fab_state_config.py Outdated
Comment thread src/fabric_cli/core/fab_auth.py Outdated
Comment thread src/fabric_cli/core/fab_context.py Outdated
Comment thread src/fabric_cli/core/fab_logger.py Outdated
Comment thread src/fabric_cli/core/fab_logger.py Outdated
Comment thread src/fabric_cli/core/fab_logger.py Outdated
Comment thread src/fabric_cli/core/fab_logger.py Outdated
Comment thread src/fabric_cli/core/fab_logger.py Outdated
Move _write_restricted_file, _chmod_if_posix, and directory creation
logic into a dedicated fabric_cli.utils.fab_file_permissions module.
This addresses review feedback that classes should not depend on
fab_state_config just for file permission functionality.

Changes:
- New utils/fab_file_permissions.py with _IS_POSIX constant,
  chmod_if_posix(), write_restricted_file(), create_restricted_dir()
- fab_state_config.py: remove local helpers, import from utils
- fab_auth.py: import from utils instead of fab_state_config
- fab_context.py: import from utils instead of fab_state_config
- fab_logger.py: remove local _chmod_if_posix, use shared helpers,
  add _RestrictedRotatingFileHandler to enforce 0o600 on rotated
  log files, add warning on chmod failure
- Update test mocks to reference new module path

Assisted-by: GitHub Copilot:claude-opus-4.6
Copilot AI review requested due to automatic review settings June 15, 2026 16:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Comment thread src/fabric_cli/utils/fab_file_permissions.py Outdated
Comment thread src/fabric_cli/core/fab_logger.py Outdated
Comment thread src/fabric_cli/utils/fab_file_permissions.py Outdated
Comment thread tests/test_core/test_fab_state_config.py
Explicitly set encoding='utf-8' in os.fdopen for consistent JSON
persistence across platforms and locales.

Assisted-by: GitHub Copilot:claude-opus-4.6
Comment thread src/fabric_cli/core/fab_auth.py
Comment thread src/fabric_cli/utils/fab_file_permissions.py Outdated
Comment thread tests/test_core/test_fab_logger.py Outdated
Comment thread src/fabric_cli/utils/fab_secure_io.py
Comment thread tests/test_core/test_fab_auth.py Outdated
Comment thread tests/test_core/test_fab_auth.py Outdated
Comment thread tests/test_core/test_fab_logger.py
…on tests

- Rename fab_file_permissions.py to fab_secure_io.py for clarity
- Change chmod_if_posix log level from warning to debug
- Add _success suffix to all permission test names
- Add log file permission test (0o600 + owner readability)
- Add log rotation permission test (rotated files maintain 0o600)
- Clarify 'old CLI version' comments in test assertions

Assisted-by: GitHub Copilot:claude-opus-4.6
Copilot AI review requested due to automatic review settings June 16, 2026 15:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread src/fabric_cli/utils/fab_secure_io.py Outdated
Comment thread src/fabric_cli/core/fab_logger.py
Comment thread tests/test_core/test_fab_logger.py
iemejia added 3 commits June 16, 2026 17:32
…ndler cleanup

- Tighten permissions before truncation in write_restricted_file() to
  close the race window on pre-existing files
- Rename _IS_POSIX to IS_POSIX (public constant) in fab_secure_io
- Add handler cleanup in log file permission test to prevent
  accumulation on the global logger singleton

Assisted-by: GitHub Copilot:claude-opus-4.6
Black does not read configuration from tox.toml. The target-version,
line-length, and exclude settings defined there were silently ignored.
Move them to pyproject.toml where Black actually reads them.

Assisted-by: GitHub Copilot:claude-opus-4.6
Copilot AI review requested due to automatic review settings June 18, 2026 06:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread src/fabric_cli/utils/fab_secure_io.py
iemejia

This comment was marked as off-topic.

iemejia

This comment was marked as off-topic.

iemejia added 2 commits June 18, 2026 09:37
…elper

Move restricted file opener logic from fab_logger.py into
fab_secure_io.py as get_restricted_file_opener(), which returns the
POSIX opener or None on Windows.  fab_logger.py no longer imports
IS_POSIX directly.

Assisted-by: GitHub Copilot:claude-opus-4.6
Comment thread pyproject.toml Outdated
Copilot AI review requested due to automatic review settings June 18, 2026 09:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@aviatco aviatco merged commit b0969bd into microsoft:main Jun 18, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Auth, config, context, and log files created with world-readable permissions on Linux/macOS

3 participants