Skip to content

[Bug] turn-diff follows symlinks out of the workspace, both when it captures files and when it applies a change #525

Open

Description

@modacker

Title

turn-diff follows symlinks out of the workspace, both when it captures files and when it applies a change

Where

packages/local-runtime/src/turns/file-changes.ts

  • the capture path (snapshotCapturedFiles / snapshotCapturedFile) resolves a
    recorded path against the workspace root and then reads it
  • the mutation path (resolveMutationTargetPath / applyLocalTurnDiffSnapshotMutation)
    resolves the recorded path and writes there

Reproduction

  1. In the workspace root, create link -> /outside/secret.txt where
    /outside/secret.txt holds text the agent should never see.
  2. Let the agent write to link.
  3. Ask for the turn's diff.

The captured entry contains the content of /outside/secret.txt, and the
recorded path is the symlink itself.

The reverse direction is the same: the diff lists link, and applying or
reverting it writes to /outside/secret.txt.

Impact

  • content from outside the workspace is captured into the session's stored
    turn diff and is returned to the client
  • a change recorded under a symlink name is applied outside the workspace
  • the permission layer does not see it, because it compares paths lexically:
    a symlinked path inside the workspace produces no approval prompt at all

Expected

The target of a captured or applied change has to sit inside the workspace
after symlinks are resolved. A dangling symlink needs the same treatment:
realpath fails for it exactly as it does for a missing file, but writing
through it creates the file it points at.

Notes and limits

  • resolving the real path and then opening the file leaves a race: the link can
    be swapped between the check and the open. Closing that needs an
    O_NOFOLLOW-style open, which is a larger change.
  • a symlink inside the workspace that points at another location inside the
    same workspace keeps working; only escapes are refused.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions