AI Agents on Linux: Two Threat Models

Necco Ceresani
Necco Ceresani··26 min read

Fifteen years building engineering platforms, currently focused on advanced AI infrastructure at yeet. I love turning the deeply complex topics into something everyone can understand. I relate deeply with the core yeet philosophy that you can just build things.

Last updated: September 2026

Quick answer. There are two different security problems wearing the phrase "AI agent security", and they point in opposite directions. The first protects the agent from the infrastructure it runs on: confidential computing, TEEs, attested TLS, and the adversary is the host administrator. The second protects your infrastructure from the agent: what it reads, what it runs, what it sends, and the adversary is an agent that was working correctly right up until it wasn't. Buying the first does not give you the second. The tell is which direction the isolation points, and a stack whose whole purpose is to make the kernel unable to observe the workload has answered a question most teams running coding agents were not asking.

I'm Necco, and I run yeet, a JS runtime for writing eBPF programs that thousands of engineers use to see what their Linux boxes are doing. I sell tools that live on one side of the split this post is about, so read the argument accordingly: I have a commercial interest in you caring about the second threat model. I have never run a confidential computing deployment in production, and the people who do are solving a real problem I am not going to talk down.

What I keep running into is a conversation that goes wrong in a specific place. Someone asks how to secure the agents they've started running on their build hosts, and the answers they get back are about enclaves and attestation, and none of it touches the thing that is actually bothering them, which is that a process on their machine is deciding what to read and nobody can say afterward what it read. Both sets of tools are good. They are answers to different questions, and the phrase in the middle is doing damage.

Why does my AI agent run the right Linux command and still get the host wrong?

An agent needs ground truth about the host, not more knowledge of Linux. Current models write correct ss, lsof, journalctl and systemctl invocations without help, and the failure you actually see is not a model that misremembers a flag. It is a model that runs the right command against a machine it cannot see the state of, gets output shaped by conditions it doesn't know about, and reasons confidently from it.

This is worth stating plainly because "which agent should I use on Linux" is the wrong first question. Claude Code, Codex, Cursor, Aider, Cline and the self-hosted options all know Linux administration. The differences between them are ergonomics, context handling and cost, and none of those differences change what happens when the agent needs a fact about your host that no command in its training set can supply, because the fact is about right now.

The gap is instrumentation, and specifically instrumentation you can add after you already have the question. A model knows what ss -tnp does. It cannot know which of the eleven connections that returns belongs to the process it just started, unless something on the host is recording the association. Static instrumentation doesn't help either, because the thing you want to watch today is not the thing you knew to watch when you deployed the monitoring.

There is a version of this that shows up in every agent session long enough to matter. The agent needs to know whether the thing it just started is working. It has no way to watch the process it launched, so it reaches for the tools that print a snapshot, gets a snapshot, and reasons about a moving system from a still image. Then it runs the command again a few seconds later and gets a different still image, and now it has two frames and no motion. The competent thing to do at that point is attach to the process and watch, and that is the one move it cannot make without something already on the host to do it with.

Two consequences follow, and they set up the rest of this post. The first is that agent capability on Linux is bounded by observability, not by training. The second is that the same instrumentation gap that limits what an agent can know also limits what you can know about the agent. Those turn out to be the same problem seen from two ends, which is why a team that fixes the second usually finds it has fixed the first as well.

Do I need confidential computing to run an AI agent on Linux?

Only if someone who administers the machine is in your threat model, which is what putting the kernel on the adversary list means. This is the first threat model, it is coherent and well-developed, and the Confidential Computing Consortium states it about as clearly as it can be stated. From their January 2026 piece on protecting agentic AI workloads:

"In order to operate safely and as expected, Agents need to be isolated from the infrastructure on which they are running, breaking the standard model of computing where whoever controls the infrastructure controls the workloads."

Read the second half of that sentence again, because it is the whole distinction in fifteen words. The standard model of computing is that whoever controls the infrastructure controls the workloads. This threat model deliberately breaks it. The same piece is explicit about who is being kept out: agent memory is "protected from tampering and viewing by all other entities with access to the machine, including administrators, the kernel and hypervisor."

The kernel is on the list of adversaries. That is not a criticism, it is the design, and for the problem it addresses it is the correct design. The problem is real: you run an agent on someone else's hardware, that agent holds a credential or a customer's data, and you would like a guarantee that the cloud operator cannot read it. The survey literature on TEEs for agentic AI frames the same adversary, noting that current defenses "operate entirely within the software stack and can be silently bypassed by a sufficiently privileged adversary such as a compromised cloud operator." Intel SGX, Intel TDX, AMD SEV-SNP, ARM CCA and the H100's confidential mode all exist to close that gap, and attested TLS extends it to the channel so a peer can verify which enclave it is talking to.

If you are building a platform that runs other people's agents, this is your threat model and you should take it seriously. If you are a company that has started running coding agents on your own build hosts, it is not, and it is worth being precise about why. You are the administrator. You control the infrastructure. There is no untrusted operator in your picture, because the operator is you.

What is stopping Claude Code from reading ~/.ssh on my Linux box?

Usually nothing, and this is the model most teams running agents in 2026 actually have. The agent is a process on a host you own. It runs as a user you created. It inherits every permission that user has, and it decides what to do with them while it runs rather than at the time you granted them.

Anthropic's own sandboxing documentation is direct about where that leaves the default. On the Claude Code sandboxing page, the default read scope is described as:

"Default read behavior: read access to the entire computer, except certain denied directories. Note that this default still allows reading credential files such as ~/.aws/credentials and ~/.ssh/."

The same page states the reason both isolation layers matter, in a sentence that names the adversary as the agent: "Without network isolation, a compromised agent could exfiltrate sensitive files like SSH keys. Without filesystem isolation, whether from a permissive policy or from disabling the filesystem layer, a compromised agent could backdoor system resources to gain network access."

Credit where it is due, because that is a vendor documenting the sharp edges of their own defaults rather than describing the feature and stopping. It is also the exact inverse of the first threat model. Here the agent is what you are defending against and the host is what you are defending. There, the host was what you were defending against and the agent was what you were defending.

Both sentences are true. They cannot both be describing the same product category.

What makes this threat model specifically about agents, rather than a restatement of ordinary process isolation, is predictability. A deploy script runs the commands someone wrote in it. A CI job runs a pipeline definition you can read in advance, which means the set of things it might touch is enumerable before it runs, which in turn means a policy can be written from the definition. An agent's actions are chosen while it runs, from context that includes files it read a moment ago and output from commands it just executed. You cannot derive the policy by reading the job, because there is no job to read.

That difference is why the recording half carries more weight for agents than it does for anything else running on the same host. With a CI job, a tight sandbox is close to sufficient, because you enumerated the paths and the enumeration was correct. With an agent, the sandbox covers what you anticipated and the recording covers the rest, and the rest is where the interesting failures live.

Protect the agent from the hostProtect the host from the agent
AdversaryCloud operator, administrator, hypervisor, kernelThe agent's own next action
TrustedThe agent, its code and its missionThe host, its operator and its kernel
Typical stackIntel TDX, AMD SEV-SNP, ARM CCA, attested TLSLandlock, seccomp, BPF LSM, egress policy, kernel audit
Question answeredCan the operator read my agent's memory?What did my agent read, run and send?
Buy it whenYou run agents on hardware you don't controlYou run agents on hardware you do control
What it does not addressAn agent misusing access it was legitimately givenAn operator reading the agent's memory

The conflation is not usually anybody lying. It is that "AI agent security" is a phrase both industries reasonably use, and a team searching it finds whichever one markets harder. The check that resolves it takes about ten seconds: ask which direction the isolation points. If the mechanism is making it harder for the machine's owner to see inside the workload, it is model one. If it is making it harder for the workload to affect the machine, it is model two. A stack that does the first cannot do the second, because they are the same wall facing opposite ways.

How do I audit what an AI agent actually ran when OTEL_* stops at Bash?

Record it at the kernel, because everything else in the picture is written by something the agent participates in. An agent is a process on a Linux host, and the kernel mediates everything that process does regardless of whether the agent cooperates: every execve, every open, every outbound connection, every child process and everything those children do.

Most of what gets called agent monitoring today is instrumentation the framework opts into: callbacks, SDK hooks, OpenTelemetry spans, the tool-call log. Those are useful and they are not evidence, because their scope is bounded by what the framework mediates. Anthropic documents one such boundary directly, and it is the cleanest example of the general problem: OTEL_* environment variables are not passed to the subprocesses the Bash tool spawns. The agent's log therefore records that a shell command ran, and the commands underneath it are outside the record. The full walk through that boundary is its own post, including what auditd and strace each catch and where they stop.

The distinction worth carrying is between a report and an observation. A report is produced by the thing being reported on. An observation is produced by something else. When an agent's telemetry and a kernel record disagree, you want to already know which one you would believe.

This is not a claim that agent frameworks are dishonest, and it is worth separating the two arguments because they get bundled and the weaker one drags down the stronger. The weak argument is that an agent might lie about what it did. That is possible and it is not the common case. The strong argument is that an agent's telemetry has a scope, the scope is set by what the framework mediates, and an action that happens outside that scope produces no record at all rather than a wrong one. A silent gap is worse than a wrong entry, because a wrong entry is visible.

The same reasoning applies to anything that asks the agent to cooperate, which includes most of what is currently sold as agent observability. A callback fires when the framework calls it. An SDK hook records what passes through the SDK. A proxy sees what is routed through the proxy. Each is real telemetry with a real boundary, and the boundaries are all drawn in the same place: around the part of the system the agent's own code is participating in.

Here is the difference made concrete. Run any agent, ask it to do something ordinary, and watch what the kernel says it launched:

yeet run exectop --comm claude

exectop attaches to the kernel's process-execution path and prints one row per kind of command, folded by count, with the process that launched it. --comm claude scopes it to the agent's process tree. What comes back is every binary the agent invoked, including the ones that ran inside a shell one-liner the agent's own log records as a single tool call. You do not have to configure the agent, and the agent is not asked to participate.

That is the whole architectural claim. The trustworthy observation boundary sits below the thing being observed. It is the same reason you don't ask a process to report its own CPU time.

Do I need a TEE to run AI agents on my own Linux build fleet?

No, and almost certainly the second threat model is yours, if you administer the machines. The test is one question: is there anyone in your threat model who can read the agent's memory and whom you have not already trusted with everything else on that box? For a company running coding agents on its own build fleet, the answer is no, and it stays no until the day you start running agents on behalf of customers who need a guarantee about you.

Where it gets properly mixed is a platform that runs other people's agents. Then you have both, simultaneously, pointed at each other: your customers need model one against you, and you need model two against their agents. Those requirements are in real tension, and resolving it is a design problem rather than a purchasing one. The honest version is that you cannot both blind yourself to a workload and audit it, so what you can offer is attestation over an enforcement policy: prove which rules were running, rather than prove what the workload did.

Worth saying plainly: if you are in that position, the first threat model is not optional and nothing in this post substitutes for it. Every route below assumes you are the operator and you trust yourself.

Should I sandbox an AI agent on Linux with Landlock, or record it with exectop?

Both, because they fail in opposite directions and each covers the other's failure. Confinement decides what the agent can do before it acts, which means it only covers the paths you thought to enumerate. Recording covers the actions you did not anticipate, and only after they have completed.

The realistic routes, on a host you own:

yeet scripts (exectop, agent-lock, agent-jail) put the record and the enforcement in the same runtime, at the kernel, in JavaScript you can edit while it runs. agent-lock refuses an open outside your project directory with a BPF LSM hook and streams every attempt it refused. That last part is the one to weigh: a denial you cannot see is a policy you cannot debug. The tradeoff is that this needs a kernel new enough for BPF LSM and a root-capable install, so it is a fleet decision rather than a laptop one.

Landlock is the right answer when you cannot load BPF. It is unprivileged, it is in mainline, it was built for exactly this, and agent-jail takes that route and enforces on the inode so hardlink tricks resolve to the same refusal. It confines and it does not report, so pair it with something that does.

The agent's own sandbox is already on the machine and is worth turning on before anything else. Claude Code's ships on bubblewrap on Linux, its credentials setting will deny ~/.ssh and ~/.aws/credentials specifically, and its documented default read scope is the whole computer, so turning it on is a real change rather than a formality. It governs the agent's Bash subprocesses rather than the agent's own reads, which is the scope limit to hold in mind.

Containers and VMs are the correct choice when the agent is running untrusted code or you need a reproducible environment, and they are not an access-control answer. A container handed a credential and a route to your internal network has been handed those things.

Egress policy is the half most often skipped, and a hostname allowlist is not a route. The exfiltration path through an allowed domain is worth understanding before you rely on one.

RouteWhat it does betterWhat it does not cover
agent-lock, exectop on yeetKernel-side record and refusal in one runtime, editable liveNeeds BPF LSM and a privileged install
Landlock / agent-jailUnprivileged confinement, inode-accurate, mainlineConfines without reporting what it refused
Claude Code sandboxAlready installed, zero setup, denies credential pathsGoverns Bash subprocesses, not the agent's own reads
Container or VMReproducible, correct for untrusted codeDoes not constrain access you deliberately granted
auditdShips with the distro, familiar to complianceNoisy at agent volumes, no per-agent scoping

The layer-by-layer comparison of the confinement options is its own post, including what each one costs to run.

How do I tell which of five AI agents sharing a Linux uid ran a command?

Attribute by process tree, because nothing above the kernel can tell two agents apart reliably. A host running three coding agents, a background review agent and whatever an MCP server spawned has five independent decision-makers sharing one uid, one filesystem and one egress path. The user-level permission model has no vocabulary for this: to the kernel's ownership checks they are all the same principal, which means every one of them can read everything the others can.

This is where the two threat models stop being a clean either-or for teams that thought they only had the second one. Agents increasingly coordinate, which means one agent's output is another agent's input, and an agent reading instructions from a peer is trusting a channel it cannot verify. That is a model-one problem (protect this agent from an untrusted source) appearing on infrastructure you fully control, and the confidential computing stack is not what solves it there, because the untrusted party is inside your trust boundary rather than outside it.

The tractable part is attribution, and it is worth doing before it is urgent. Scope every record to a process tree rather than a user, so "the agent read this" is a statement about a specific agent. exectop --comm does this by process name; for coordinated agents the more durable key is the tree root, since a subprocess three levels down still resolves to the agent that started the chain. Without that, an incident review of a multi-agent host produces a list of things that happened as one user, and no way to say which decision-maker made any of them.

How do I give an AI agent access without putting a key in ~/.aws/credentials?

Make the credential unreadable rather than making the agent trustworthy. An agent that can read a key can use the key, and can be persuaded to use it, and every mitigation downstream of that fact is working against a broad grant that was made at the start.

The reason this is structural rather than a configuration mistake: file-based credentials were designed for a user who reads them deliberately, and an agent's whole operating mode is to search the filesystem for whatever seems relevant to the task. ~/.aws/credentials is a plausible-looking file to a process that is looking for plausible files. The permission model does not distinguish "the user opened this" from "a process running as the user opened this", which is precisely the distinction that matters now.

Three things that actually change the shape:

  • Deny the paths explicitly. Claude Code's credentials setting blocks reads of ~/.ssh and ~/.aws/credentials and unsets named environment variables per command. It is the shortest path from the default to something defensible, and the default does not do it for you.

  • Broker the credential instead of storing it. The agent asks for an operation and something else holds the key. This is a larger change and it is the one that actually removes the class.

  • Record what reached for what. Whatever else you do, know which process opened which credential file, because the alternative is finding out from someone else.

I want to be careful about the limit of my own claim here. Nothing at the kernel makes a credential safe to hand out. agent-lock refusing an open on ~/.ssh is a narrower guarantee than a key the agent could never read in the first place, and a brokered credential beats a denied path every time it is available. The kernel route is what you reach for when the credential has to exist on the box.

The bottom line: pick the model that matches who you don't trust

Work out which adversary is in your picture before you buy anything, because the two stacks do not substitute for each other in either direction. If you run agents on infrastructure you do not control, or you run them on behalf of customers who need a guarantee about you, you need confidential computing and attested TLS and this post has nothing better to offer you than the Confidential Computing Consortium's own material. If you run agents on your own hosts, turn on the sandbox that shipped with your agent first, because it is free and its default read scope is the entire computer. Add Landlock or agent-jail when you need confinement on a machine where you cannot load BPF, and a container when the agent is running code you did not write. Reach for agent-lock and exectop on yeet when you want the refusal and the record in one place and you can run privileged on the fleet. Use auditd if compliance already reads its output and nobody wants a new pipeline.

The failure worth avoiding is subtler than picking the wrong tool. It is buying hardware isolation that guarantees you cannot inspect a workload, to solve a problem you described as "I don't know what my agent is doing on my own machines". That purchase makes the stated problem permanently unsolvable, and it will pass every review on the way through, because the phrase on the box matched the phrase in the ticket.

Frequently asked questions

What is the difference between a TEE and a sandbox for AI agents?

A TEE hides the workload from the machine it runs on, and a sandbox limits what the workload can reach on that machine. They face opposite directions: an enclave keeps the host's administrator out of the agent's memory, while Landlock, seccomp or a BPF LSM hook keep the agent out of the host's files and sockets. Neither substitutes for the other, and a team that buys an enclave to answer 'what is my agent doing on my servers' has made that question harder to answer rather than easier.

Can I trust an AI agent's logs?

Treat them as testimony rather than evidence. An agent's telemetry is written by the agent framework, records what the framework chose to record, and stops at the boundary of what the framework controls. Anthropic documents one such boundary directly: OTEL_* environment variables are not passed to the subprocesses the Bash tool spawns, so the log names the tool call and not the commands underneath it. A kernel-side record is produced by something the agent does not author.

Should AI agents have production access to Linux servers?

The question is better asked as which access, granted for how long, and recorded by whom. An agent inherits every permission of the user it runs as, and it decides what to read on its own, so a normal user account is a broad grant. The workable pattern is narrow filesystem and egress scope, credentials that are not readable as files, and a record of what the agent did that the agent did not write.

What is the difference between sandboxing an AI agent on Linux and monitoring one?

Sandboxing decides what an agent is able to do before it acts, and monitoring records what it did. They fail differently: a sandbox that is scoped too broadly permits the thing you cared about and reports nothing, while monitoring catches an action you did not anticipate but only after it completed. Most teams need a narrow sandbox for the paths they can enumerate and a kernel-side record for everything they could not.

Do AI agents need to be trained on Linux?

No. Current models know Linux administration well and can write correct commands for most tasks without help. What a model cannot know is the state of your particular host: what is listening on a port right now, which process is holding a file, what the agent it is coordinating with just did. That gap is closed by instrumentation, not by training or fine-tuning.

Does running an AI agent in a container protect my host?

It protects the host filesystem and it does not protect anything the container can reach. A container that is given credentials, a network route to your internal services, or a mounted source tree has been given those things regardless of the isolation boundary. Containers answer the question of what the agent can touch on this machine, and not the question of what it can do with the access you deliberately handed it.

What can the Linux kernel see that an AI agent's telemetry cannot?

Every process the agent spawns and everything those processes do, including file opens, network connections and further subprocesses. The agent's framework records the actions it mediates, so an action taken by a child process is outside what it observes. Kernel-side records come from hooks the agent's code does not participate in, which is what makes them usable as evidence rather than as a report.

Is an AI agent a different security problem than a CI runner?

Mostly the same primitives, different predictability. A CI job runs a script someone wrote and reviewed, so its actions are enumerable in advance. An agent decides what to run while it runs, which means access-control policy cannot be derived from reading the job definition beforehand. That is why the recording half matters more for agents than it does for CI.

Can an AI agent read my SSH keys?

By default, on most setups, yes. Claude Code's sandboxing documentation states that its default read behavior is read access to the entire computer except certain denied directories, and notes that this default still allows reading credential files such as ~/.aws/credentials and ~/.ssh/. The sandbox ships a credentials setting to deny those paths specifically, which is worth turning on.

Does attested TLS solve AI agent security?

It solves agent identity and channel integrity, meaning a peer can verify it is talking to the agent it expected inside a verified enclave. It says nothing about whether that agent's next action is one you wanted. An authenticated agent taking a harmful action is still taking a harmful action, and the attestation is what proves it really was your agent that took it.

Sources

  • Protecting Agentic AI Workloads with Confidential Computing. Confidential Computing Consortium, January 2026. The clearest published statement of the first threat model. States that agents "need to be isolated from the infrastructure on which they are running, breaking the standard model of computing where whoever controls the infrastructure controls the workloads", and lists the adversaries explicitly as "administrators, the kernel and hypervisor". The source for this post's spine.

  • Claude Code sandboxing documentation. Anthropic. Documents the default read scope as "read access to the entire computer, except certain denied directories" and notes it "still allows reading credential files such as ~/.aws/credentials and ~/.ssh/". Also states why both isolation layers are needed, naming a compromised agent as the adversary in both directions. The credentials and filesystem settings referenced in this post are specified here.

  • When Agents Handle Secrets: A Survey of Confidential Computing for Agentic AI. Forough, Kogias and Haddadi. Survey covering six TEE platforms and an agent-centric threat model across perception, planning, memory, action and coordination. Frames the adversary as "a sufficiently privileged adversary such as a compromised cloud operator", which is the first threat model stated in research terms rather than vendor terms.

  • Landlock. The unprivileged access-control LSM in mainline Linux, and the right confinement route on hosts where loading BPF is not an option. Documents the ruleset and inode-based enforcement model that agent-jail builds on.

  • agent-jail. Landlock-based confinement for a coding agent, enforcing on the inode so hardlink and symlink traversal resolve to the same refusal. The ready-made tool for the Landlock route in the table above.

  • yeet documentation. The JavaScript runtime the kernel-side scripts in this post are written in, including the BPF LSM and process-execution surfaces agent-lock and exectop attach to.

Related resources