Skip to content

security(sandbox): concurrent grant writes can resurrect revoked permissions #752

Description

@PierrunoYT

Summary

Persistent sandbox grant read-modify-write transactions are protected only by an in-process mutex belonging to one GrantStore instance. Two separate zero processes can each read the same on-disk grants file, and the second process's atomic-rename write can overwrite the first — including silently restoring a grant the first process had just revoked.

Affected code

  • internal/sandbox/grants.go:121-150
  • internal/sandbox/grants.go:298-320
  • internal/sandbox/grants.go:371-391
  • internal/sandbox/grants.go:591-607

Configuration writers have the same lost-update pattern in internal/config/writer.go:14-55 and internal/config/writer.go:744-778, though there the usual impact is lost settings rather than a restored security permission.

Race outline

  1. Process A and Process B both read the current grants file into memory.
  2. Process A revokes a grant and atomically writes back the file (write-temp + rename).
  3. Process B, still holding its earlier in-memory read (which still includes the grant A just revoked), later writes back its own state and atomically overwrites A's file.
  4. The revoked grant is now restored on disk, silently reinstating access that was supposed to be gone — with no indication to either process or the user that the revocation didn't stick.

Impact

Atomic rename prevents malformed/corrupted JSON on disk, but not this lost-update pattern. A stale writer can restore a persistent sandbox grant (e.g., a command-prefix or path allow) that another process deliberately revoked moments earlier.

Suggested fix

Acquire an interprocess lock around the complete read-modify-write transaction (not just the in-process mutex), and re-read the file's current contents after acquiring that lock, immediately before mutating and writing back.

Reference

Item AUD-005 from the 2026-07-18 codebase audit (docs/CODEBASE_AUDIT_2026-07-18.md).

Metadata

Metadata

Assignees

No one assigned

    Labels

    issue-approvedReviewed and approved by the core team; community PRs may implement this issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions