All Field Notes
Issue 13Building with AI

The AI agent that tried to make itself at home on my machine

No prompt had been sent and no model had run, but a startup probe still reached for the shared Codex state on my machine before the sandbox stopped it.

6 min read

The startup probe should have been quiet. No prompt had left the app, no agent response existed, and no model turn had been consumed, but it still stopped on a filesystem denial: a local process was trying to create runtime state inside the normal Codex home used by the rest of my work.

The attempted write never succeeded, and no model turn had been started because the sandbox did exactly what it was there to do; however, the destination made the result hard to dismiss. This process was supposed to belong to Roughwise, not wake up inside the same state boundary as my other Codex conversations, project settings, and authentication on my machine.

Roughwise is a local-first desktop application that takes an early product idea, structures its evidence and open questions, and can eventually prepare an approved project for development. The integration work was connecting it to Codex through a local App Server with a narrow promise: stream one structured assessment without gaining access to other projects or execution authority. If that promise was already bending before the model started, which part of the system was actually isolated?

Read-only only describes part of the system

The first security plan sounded strict: disable tools, deny approvals, remove network access from tool execution, accept only structured output, and keep every final decision behind deterministic product rules and human approval.

Those controls mattered, though they began too late. Before a model could request a command or propose an assessment, the executable had already started as a normal process on my machine, where it could inherit a home directory, environment variables, working-directory context, configuration, authentication state, plugins, and access to services the product never intended to expose.

Calling the agent “read-only” therefore described its allowed task, not its complete operating environment.

What read-only appeared to guarantee

  • No shell commands
  • No model-authored file changes
  • No web research or external tools
  • Structured assessment output only
  • No authority to promote a project

What isolation also had to control

  • Which home directory receives runtime state
  • Which working directory the process can identify
  • Which credentials and variables it inherits
  • Which executable and protocol version actually runs
  • Which requests, notifications, and partial results are accepted

The distinction matters outside security engineering. A founder can approve a “no tools” AI feature believing it cannot affect local work, while the integration still reuses a personal account, writes shared state, loads ambient configuration, or mixes one workspace's state with another. No malicious prompt is required because the problem exists before prompting begins.

The boundary had to move outward

The failed probe made the safer architecture concrete. Roughwise gave the child process its own application-owned Codex home and an empty working directory instead of pointing it at a real project. It launched with a minimal environment that excluded ambient credentials and the normal home, while the exact reviewed Codex executable version was pinned rather than accepting whichever compatible-looking binary happened to be installed later.

Tools and integrations were still disabled, but now they were the inner layer rather than the whole defense. Roughwise also treated server requests and action-bearing notifications as policy violations, bounded the size of protocol lines and pending messages, gave cancellation priority over queued completion, and accepted a final assessment only after it passed the product's own schema and dossier rules.

Provenance needed the same treatment. A model could select only references included in the request, while Roughwise reconstructed their text and timestamps from trusted local sources. That prevented a structurally valid response from inventing where a claim came from or making an older profile revision look like evidence captured with the current idea.

Contain the integration before trusting the answer
  1. Pin the reviewed executable
  2. Start inside an application-owned home and empty workspace
  3. Strip ambient credentials and integrations
  4. Reject action-bearing protocol traffic
  5. Bound streams, cancellation, and failure states
  6. Reconstruct provenance from trusted local sources
  7. Validate the final assessment before it becomes product state

None of those controls makes the model smarter, but they make its operating context narrower, more reproducible, and easier to explain when something fails.

The happy path was still too optimistic

Once the isolated startup worked, the adapter passed its focused tests and the interface clearly disclosed network and unpriced account usage. It would have been easy to treat that as sufficient evidence, especially because no real model turn was required to verify most of the boundary.

An independent security review still blocked the implementation on three medium-severity problems. A failed protocol queue was not always terminal, malformed known notifications could be ignored instead of stopping the run, and one profile timestamp came from the idea rather than the profile revision that supplied the evidence.

These were not dramatic remote attacks; however, they were exactly the kind of small inconsistencies that turn a strict policy into a hopeful one. If processing can continue after the parser has lost confidence, a later message may appear valid without a trustworthy chain leading to it. If malformed activity is ignored, “unknown” quietly becomes “allowed.” If provenance uses the wrong time, the product can present accurate text with inaccurate history.

The fixes added terminal failure handling, stricter notification rejection, request-bound provenance, cancellation ordering, and adversarial regressions. The corrected boundary passed 39 focused runtime and transport tests, the full 257-test unit suite, packaging checks, desktop smoke tests, and a second independent review with no remaining high- or medium-severity findings.

The model call is not the beginning

This evidence supports a narrow claim: the reviewed Roughwise integration contained the startup and protocol paths it exercised, but it does not prove that every future Codex version is compatible or that directory identity checks can defeat a malicious process already running as the same operating-system user.

Nonetheless, it changes where AI product review should begin. Prompt boundaries, tool permissions, output schemas, and approval screens are visible and important, but they sit inside an older kind of software boundary made of processes, files, identities, configuration, queues, and failure states.

If an embedded agent must not touch another project, reuse another account, or turn uncertain output into product truth, disabling its tools is only one layer. The integration is isolated only when the whole path from process startup to accepted result has nowhere else to go.