Letting a Model Call Your Code Safely
Nothing in the Environment Worth Stealing
Last timeCutting the Network
A submission that can read a secret needs no connection to steal it, because the service returns whatever the program printed, so the secret has to be absent rather than guarded.
Where a secret can be, from the submission's side
The previous lesson ended with no route out, which closed two of the ten things
a hostile submission tries. This lesson is about the item that reads a file
holding credentials, and it is more awkward than the network, because the honest
version of the question is not how a secret gets out. It is where a secret is in
the first place.
A submitted program sees four places and one thing that is not a place. The
environment it was handed. The files it can open. The process that surrounds it,
which the kernel is surprisingly willing to describe. And the other processes
running under the same identity. The thing that is not a place is the machine's
own identity in the cloud, which belongs to the host rather than to any of those
four and survives emptying all of them.
| arrives without the submission asking | readable with no network at all | closed by cutting the network | how badly it needs its own rule, 0 to 3 | |
|---|---|---|---|---|
| the runner's own environment | 1 | 1 | 0 | 3 |
| the command line it was started with | 1 | 1 | 0 | 2 |
| the host's files under a read-only root | 1 | 1 | 0 | 3 |
| other submissions' processes under one identity | 1 | 1 | 0 | 2 |
| the machine's identity in the cloud | 0 | 0 | 1 | 3 |
The first column is worth a second look as well. Four of the five arrive without
the submission doing anything at all. They are not reached for, they are
inherited, which is why none of them can be defended by watching for an attempt.
The environment is a value, not a permission
The most common way an operator hands a secret to a stranger's program is by
putting it in the environment of the service that runs the program. It happens
because the environment is where configuration lives, and nobody thinks of
configuration as a thing that gets handed on.
A permission is checked at the moment it is used, which is what makes it
refusable. The environment is not like that. It is copied into a child process
when the child is created, so by the time the submitted program is running there
is no decision left to be made and nothing for a check to hook onto. The
submission does not read the runner's environment. It reads its own, which is a
copy, and the copy was made by the runner.
So the rule is a deletion and it has to happen before the process exists. The
runner in this service carries 40 variables, most of them put there by the
platform it runs on and several of them credentials for things that have nothing
to do with running submitted code. The submitted program needs three: where its
scratch folder is, which locale to format in, and a minimal search path. That
leaves 40 minus 3, which is 37 variables deleted, and the deletion is an allow
list for the same reason the network rule was.
The lesson stops here
7 more paragraphs to go
You have read the opening. The rest of the argument, the problems that check whether it landed, and the lines worth keeping at the end all come with a plan.
The first lesson of every course in the library reads the whole way through, free, so you can see exactly what the rest of them are.
See the planThe contentsThis is the reading half
Starting the course gives you your own copy of it. Every idea on every page has problems standing under it, marked with a reason rather than a tick, and any sentence you do not believe can be opened and argued with. None of that can happen on a page nobody owns.
The contents