cujo
Skip to content
Contents

The sandbox boundary

Running a pull request means running a stranger's code. Where that happens, and what is allowed across the line.

Running a pull request means running a stranger's code

pip install alone executes a package’s setup.py before any of your own code runs.

That is not a hazard Cujo introduces; it is the hazard Cujo exists to measure. What follows from it is that all of it has to run somewhere holding no credentials, with no path back, and that gets thrown away afterwards.

Two zones, one narrow bridge

ZoneHolds
TrustedThe harness, the Cujo service, the MCP server that posts reviews, and every secret — the App’s private key, the model key, the Discord token.
Untrusted and disposableThe pull request’s code and its dependencies, the checks’ own scripts, Cujo’s sensor code, and the logging proxy. One box per turn, destroyed after it.

Four things cross into the sandbox, and one comes back:

  • The pull request’s code and its public metadata.
  • The names of the dependencies it added.
  • Cujo’s own sensor script and the commands the checks run. Ours, carrying no secret — the instrument, not the specimen.
  • A public run’s own id, so a report can name itself. An id and never a URL, so no hostname crosses either.
  • Out: JSON reports. Nothing else.
No token, key, clone credential or hostname ever enters the sandbox. That is the property the whole design protects, and it holds for a private repository too: its trees are fetched outside the box with the App’s own access and copied in, so the box clones nothing and holds nothing to clone with.

What is armed inside the box

  • A decoy secret. A plausible credentials file that nothing legitimate has any reason to open. Reading it is a hard rule.
  • A logging proxy. Every connection made through it is recorded by host, port and byte count — and only that. There is no TLS interception, so no payload is ever read.
  • A filesystem diff. Taken before and after every sensed command, hashing content wherever a silent edit would be the attack.
  • A Python audit hook. A second, independent witness to file opens, socket connects and subprocesses, which rides into every Python child including pip’s own.

The harness is also configured so that a file written inside the box cannot be fetched back out through it. The reports are the only channel.

Where it is blind, and why it says so

A sensor that can be off must say when it was off, or a quiet report reads as a clean one. So every report carries which sensors were armed and where a cap cut the evidence short, and an unarmed proxy or decoy produces a warn of its own.

The known gap is a process that opens a socket directly instead of honouring the proxy variables. That is a missed observation, not a false one — which is the direction the whole sensing design is biased in.