The first hard question a security lead asks about Occlude arrives within minutes. If the compiler reads the billing engine so that the build passes, the billing engine is in memory. Can't the contractor just read that memory?
Here is the whole answer, including the parts that don't flatter us.
Why the code is in memory at all
Occlude gives each session two sides. The person's side (their shell, editor and language server) sees the files their task needs, plus declaration stubs where their code imports something they can't read. The build's side (compiler, test runner, dev server) sees the real repository, because a build that cannot read the code does not pass.
So yes: while tsc runs, Occluded source sits in the memory of a process on the build's side. Saying otherwise would be the first false sentence in the pitch.
Who can read another process's memory
On Linux there are two ways to read another process's memory: attach to it with ptrace, or open its /proc/<pid>/mem file. The kernel applies the same rule to both. The Linux manual page for that file says it in one line:
"Permission to access this file is governed by a ptrace access mode PTRACE_MODE_ATTACH_FSCREDS check"
In an Occlude workspace the person's processes run as one user and the build's processes as another. The syscall filter denies ptrace on the person's side, and the build's processes are not even visible there. So the person's shell cannot attach to the compiler and cannot open its memory. That holds today, on the standard container runtime.
A process can always read its own memory. That matters for the second route, below.
What gVisor adds, and what it does not
A common shorthand says gVisor has no /proc/<pid>/mem. It does. gVisor's own source registers a memory file for every process, and refuses to open it without the same ptrace-attach permission Linux checks. The rule does not change on gVisor. What changes is who enforces it.
On a standard container, the line between the two users is held by the host's kernel, which every container on the machine shares. A kernel bug could let a process on the person's side cross it. gVisor puts a user-space kernel between the workspace and the host, built to expose far less of the host kernel to the code inside. That is why our hardened runtime is designed for gVisor, and why, until it ships, we say compartmented, never exfiltration-proof.
The route no runtime closes
The second route never touches memory permissions. A contractor writes a test. The test runs on the build's side, because that is where tests run. Code on the build's side can read what the build reads, from disk or from its own memory. A test that prints an Occluded file is just a test that prints a file.
Three things answer it, and none of them is a wall:
- Output from the build's side is sanitised before the person sees it: frames in Occluded files collapse to
<protected module>, and Occluded source is redacted. - Code that reads Occluded paths is flagged before it runs.
- The attempt is on the record, with the rule and the process that made it.
No filter is complete against a determined author. We call that residual structural, and we put it in writing with every customer.
Why credentials are never Occluded
Everything above concerns code the build needs. Credentials and customer data seeds are different: no build should hold them. They are Absent: not mounted, not in memory, on any runtime. When a dev server needs an API key, the key is attached to its outbound request on the way out, so the job itself holds a placeholder. The worst material is out of reach for the simplest reason. It isn't there.
What we claim
- The person's side cannot read the build's memory: different users, no
ptrace, no access to its memory file. - On today's runtime a kernel bug could cross that line. The hardened runtime on gVisor narrows it.
- Code the person gets the build to run can read what the build reads. Its output is sanitised and recorded, and the residual is stated.
- Credentials and data seeds are not in memory at all.
That is compartmented and governed. It is not exfiltration-proof, and we will not call it that.
Sources
- proc_pid_mem, the Linux manual page, on the permission check for
/proc/<pid>/mem. - gVisor's per-process files:
memInode.Openrefuses without the ptrace-attach check. - Our docs: Security model and Output sanitisation.
Want to go through this for your codebase?
Or write to contact@occludehq.com