Skip to content

fix: set secure file permissions (0600) for credential storage#353

Merged
NoeFabris merged 2 commits into
NoeFabris:devfrom
xeloxa:fix/secure-file-permissions
Feb 6, 2026
Merged

fix: set secure file permissions (0600) for credential storage#353
NoeFabris merged 2 commits into
NoeFabris:devfrom
xeloxa:fix/secure-file-permissions

Conversation

@xeloxa

@xeloxa xeloxa commented Feb 1, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR fixes a security vulnerability where antigravity-accounts.json (containing OAuth refresh tokens) was created with default file permissions (typically world-readable 0644).

Changes

  • Updated ensureFileExists to create new files with secure 0600 permissions immediately (preventing race conditions).
  • Added automatic permission fix for existing files in loadAccounts (backwards compatibility).
  • Updated saveAccounts to use 0600 mode when writing temporary files.
  • Added a cross-platform ensureSecurePermissions helper (best-effort on Windows).

Impact

Prevents local privilege escalation where other users on the system could read sensitive credentials.

@coderabbitai

coderabbitai Bot commented Feb 1, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Added ensureSecurePermissions(path) to set POSIX permissions to 0o600 where supported, invoked before reading storage in loadAccounts and loadAccountsUnsafe. writeFile calls updated to pass options { encoding: "utf-8", mode: 0o600 } in ensureFileExists (initial create) and in saveAccounts (temporary file write), so the temp file is created with restrictive permissions before rename. No exported API signatures changed.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly summarizes the main security change: setting secure file permissions (0600) for credential storage.
Description check ✅ Passed The pull request description accurately describes the security vulnerability being fixed and details all the changes made to address the issue.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Feb 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Overview

Greptile Summary

This PR addresses a critical security vulnerability where OAuth refresh tokens stored in antigravity-accounts.json were created with default file permissions (typically 0644), making them readable by all users on the system.

Changes Made

  • Added ensureSecurePermissions() helper function that sets file permissions to 0600 (read/write by owner only) on POSIX systems
  • Updated ensureFileExists() to create new files with mode: 0o600
  • Modified saveAccounts() to write temp files with mode: 0o600 during atomic writes
  • Added ensureSecurePermissions() calls in loadAccounts() and loadAccountsUnsafe() to retroactively fix permissions on existing files

Security Impact

This fix prevents local privilege escalation attacks where other users on the same system could read sensitive OAuth credentials. The implementation is comprehensive:

  • New file creation: Secured via mode option in writeFile()
  • Existing files: Permissions fixed automatically on first load via chmod()
  • Atomic writes: Temp files created with secure permissions, which are preserved during rename()
  • Cross-platform: Gracefully handles Windows and unsupported filesystems by ignoring chmod errors

The fix correctly handles all code paths where the credentials file is accessed.

Confidence Score: 5/5

  • This PR is safe to merge - it implements a critical security fix with comprehensive coverage and no breaking changes
  • The implementation is thorough and correct: (1) all file creation paths now use secure permissions, (2) existing files are fixed retroactively on load, (3) atomic writes preserve security through temp file permissions, (4) error handling gracefully supports cross-platform compatibility, and (5) the fix addresses the exact vulnerability described without introducing new issues
  • No files require special attention

Important Files Changed

Filename Overview
src/plugin/storage.ts Added secure file permissions (0600) to prevent world-readable credential storage - comprehensive fix covering initial creation, existing files, and atomic writes

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant Storage as storage.ts
    participant FS as File System
    participant File as antigravity-accounts.json

    Note over App,File: Initial File Creation (ensureFileExists)
    App->>Storage: ensureFileExists()
    Storage->>FS: access(path)
    FS-->>Storage: ENOENT (file doesn't exist)
    Storage->>FS: mkdir(dirname, recursive)
    Storage->>FS: writeFile(path, data, {mode: 0o600})
    FS->>File: Create with 0600 permissions
    File-->>Storage: File created securely

    Note over App,File: Loading Existing Files (loadAccounts)
    App->>Storage: loadAccounts()
    Storage->>Storage: ensureSecurePermissions(path)
    Storage->>FS: chmod(path, 0o600)
    Note right of FS: Fixes existing files<br/>with insecure permissions
    FS-->>Storage: Permissions updated
    Storage->>FS: readFile(path)
    FS->>File: Read credentials
    File-->>Storage: Account data
    Storage-->>App: AccountStorageV3

    Note over App,File: Saving Accounts (saveAccounts)
    App->>Storage: saveAccounts(storage)
    Storage->>Storage: withFileLock()
    Storage->>Storage: loadAccountsUnsafe()
    Storage->>Storage: ensureSecurePermissions(path)
    Storage->>FS: chmod(path, 0o600)
    Storage->>Storage: mergeAccountStorage()
    Storage->>FS: writeFile(tempPath, data, {mode: 0o600})
    FS->>File: Create temp file with 0600
    Storage->>FS: rename(tempPath, path)
    Note right of FS: Atomic operation<br/>preserves permissions
    FS->>File: Replace with secure temp file
    Storage-->>App: Save complete
Loading

@greptile-apps greptile-apps Bot 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.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps

greptile-apps Bot commented Feb 1, 2026

Copy link
Copy Markdown
Contributor
Additional Comments (1)

src/plugin/storage.ts
the ensureFileExists function creates the accounts file with insecure default permissions (typically 0644)

    await fs.writeFile(
      path,
      JSON.stringify({ version: 3, accounts: [], activeIndex: 0 }, null, 2),
      { encoding: "utf-8", mode: 0o600 },
    );
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugin/storage.ts
Line: 238:242

Comment:
the `ensureFileExists` function creates the accounts file with insecure default permissions (typically 0644)

```suggestion
    await fs.writeFile(
      path,
      JSON.stringify({ version: 3, accounts: [], activeIndex: 0 }, null, 2),
      { encoding: "utf-8", mode: 0o600 },
    );
```

How can I resolve this? If you propose a fix, please make it concise.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/plugin/storage.ts (1)

534-540: ⚠️ Potential issue | 🟠 Major

Backfill 0600 on existing credential files (not just new writes).

The change secures new temp files via fs.writeFile(..., { mode: 0o600 }), but ensureFileExists creates initial files without a mode option, resulting in default permissions (~0o644). More critically, on Unix systems fs.rename preserves destination file permissions, so existing antigravity-accounts.json at 0o644 remains insecure through upgrades unless explicitly remediated. Apply chmod during load in both loadAccounts() and loadAccountsUnsafe() so all read paths fix permissions on existing files.

🔒 Suggested chmod in load paths
+async function ensureSecurePermissions(path: string): Promise<void> {
+  try {
+    await fs.chmod(path, 0o600);
+  } catch {
+    // Best-effort: ignore on unsupported filesystems / Windows
+  }
+}
+
 export async function loadAccounts(): Promise<AccountStorageV3 | null> {
   try {
     const path = getStoragePath();
+    await ensureSecurePermissions(path);
     const content = await fs.readFile(path, "utf-8");
 async function loadAccountsUnsafe(): Promise<AccountStorageV3 | null> {
   try {
     const path = getStoragePath();
+    await ensureSecurePermissions(path);
     const content = await fs.readFile(path, "utf-8");
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 2be5a34 and 52deecd.

📒 Files selected for processing (1)
  • src/plugin/storage.ts

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@NoeFabris NoeFabris changed the base branch from main to dev February 6, 2026 14:48
@NoeFabris NoeFabris merged commit f20bf23 into NoeFabris:dev Feb 6, 2026
3 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.

2 participants