---
title: "File-read guards"
description: "Two layers that keep the model away from key folders and the pinned verifier, including through .. and symlinks."
url: https://barestate.xyz/docs/security/file-read-guards
---

# File-read guards

> Two layers that keep the model away from key folders and the pinned verifier, including through .. and symlinks.

The model should not be able to read your keys or tamper with the pinned verifier, whether it asks directly or sneaks around with `..` and symlinks. This page explains the two layers that stop that and the one gap you should know about.

Layer A is a guard that runs before every `read`, `edit`, `write`, `grep`, `find`, `ls` or `bash` call. Layer B is the task file access that the real tools use.

## Layer A: the tool-call guard

The guard denies four roots: `~/.config/solana`, `~/.ssh`, `~/.oms` and `~/.gnupg`. In a session it also protects every pinned verifier file and the task's `.git`.

| Rule | What it blocks |
|---|---|
| `denied_root` | Reads or writes under a denied root |
| `protected_write` | A write or edit to a pinned verifier file or `.git`. Reads of pinned files are allowed |
| Repetition | The same call with the same input three times in a window of 12 |
| Diff size | One write or edit over 65,536 bytes |
| Fail closed | Any exception, bad path, NUL byte or missing path blocks the call |

### `..`, `~` and symlinks

A rule on a path is easy to dodge if the path can be written a different way. So for path tools, OMS expands `~`, makes the path absolute, then resolves it with `realpath` on the deepest existing ancestor and appends the missing tail. It compares the plain and real paths, plus lower-cased variants for case-insensitive volumes. That means a `..` segment or a symlinked ancestor cannot walk around the rule, even for a file that does not exist yet.

Tests: yes. They cover `..`, symlinked ancestors, a read through a symlink into a denied root, and a `..` escape into a denied sibling folder.

## Layer B: task file access

The real file tools are the second line of defense, and they are strict about what they touch. They work only on regular files inside the task root, and they refuse a path that escapes the task through a symlink. Files open with `O_NOFOLLOW`, only regular files up to 64 KiB are allowed, and these names are refused anywhere in the path: `.git`, `.oms`, `.keys` and `.env.agent`. Writes under pinned verifier files or their ancestors are refused, including through a symlink alias. Directory listings skip symlinks.

Tests: yes, for symlinks, private names and read-only pinned files.

## Not covered

Layer A checks `~/.config/solana`, `~/.ssh`, `~/.oms` and `~/.gnupg`. Other key locations, for example `~/.aws`, have no entry in this guard. The host approval prompt and the macOS sandbox do cover `~/.aws`.
