99.99% Uptimeby Solari Status ↗

Secure Code Execution for LLM Agents (2026 Guide)

·

5 min read

·

Summarize with AI
ON THIS PAGE

The code review bot proposed a fix and a test command to prove it, and the command ended with a semicolon and something nobody on the team had written. The extra text came from a comment in the issue thread the model had read on its way to the fix. The pipeline was about to run it on the build server.

Secure code execution for LLM agents means the model's code runs on a disposable machine that holds no secrets, reaches that machine without passing through a shell, and returns output that is checked before anything trusts it. Solari provides that machine as an AI sandbox, a microVM created by API from the same account as its cloud browsers and desktops. This guide follows the code from the moment the model writes it to the moment the machine is thrown away.

Treat Model Output as Input From a Stranger

The first step is a change of mindset, because the code an agent writes is shaped by everything the agent has read. OWASP calls this indirect prompt injection: instructions hidden in a web page or a file change what the model produces, and executing arbitrary commands in connected systems is a listed outcome.

Nobody can prove what steered the model, so security lives in the path the code travels, starting with the machine it lands on.

Choose the Machine That Runs the Code

Solari sandboxes come in three isolation tiers, set with the isolation field at create time, and the table below sets them side by side.

Solari sandbox isolation tiers

A dedicated sandbox, the default, is a microVM of its own, and hardened is the same machine with outbound traffic cut. Shared is cheaper and starts faster, but it runs inside a VM shared with the organization's other shared sandboxes, separated by namespaces and a cgroup rather than a hypervisor.

Shared also hides its memory cap from the code: /proc/meminfo reports the whole VM, so a script that sizes itself from available memory can be killed without warning. For unreviewed code, hardened is the safer start, with dependencies baked into a custom template since the machine cannot download them.

With the machine chosen, the next question is how the code gets onto it.

Pass Code as Arguments, Not Shell Strings

The command line is where the opening story went wrong, so it gets its own rule. Command injection, in OWASP's description, happens when an application passes unsafe data to a system shell, and a semicolon is enough to chain a second command onto the first.

Solari's command APIs keep the shell out unless asked. commands.run takes a program and an args array, background executions treat cmd as the program with no shell, and Git commands run without a shell, so there is nothing to escape. The safe pattern is to write the model's script to a file and hand the interpreter its path:

import { SandboxClient } from "@solarisdk/sandbox"

const sandboxes = new SandboxClient({ apiKey: process.env.SOLARI_API_KEY! })
const sbx = await sandboxes.create({ template: "base", isolation: "hardened" })
await sbx.connect()

await sbx.files.write("/work/task.py", modelCode)
const res = await sbx.commands.run("python3", { args: ["/work/task.py"], timeoutMs: 60000 })
import { SandboxClient } from "@solarisdk/sandbox"

const sandboxes = new SandboxClient({ apiKey: process.env.SOLARI_API_KEY! })
const sbx = await sandboxes.create({ template: "base", isolation: "hardened" })
await sbx.connect()

await sbx.files.write("/work/task.py", modelCode)
const res = await sbx.commands.run("python3", { args: ["/work/task.py"], timeoutMs: 60000 })
import { SandboxClient } from "@solarisdk/sandbox"

const sandboxes = new SandboxClient({ apiKey: process.env.SOLARI_API_KEY! })
const sbx = await sandboxes.create({ template: "base", isolation: "hardened" })
await sbx.connect()

await sbx.files.write("/work/task.py", modelCode)
const res = await sbx.commands.run("python3", { args: ["/work/task.py"], timeoutMs: 60000 })

Once the code has run, its result deserves the same suspicion as its source.

Read Results With Checks, Not Trust

A finished command can still mislead the loop that reads it. A command that hits its deadline does not throw: it returns exitCode: -1 with timedOut set to true, so a loop that reads only the exit code can treat a half-finished run as a result.

Output size is the second check. Named shells cap each stream and set stdoutTruncated or stderrTruncated when they cut, and a truncated log handed back to the model is a partial truth.

The last check is shape. OWASP's mitigations include validating expected output formats in deterministic code, which means parsing the script's result in the orchestrator rather than asking the model whether it worked. Checked output closes the loop, but the sandbox still has doors that open from outside.

Guard the Keys That Reach the Sandbox

A locked-down sandbox can still be exposed by the identifiers around it. The sandbox id and its control and stream URLs are a credential: whoever holds them can run commands as root until the sandbox is killed or expires.

Preview links work the same way. previewUrl(port) returns a signed URL whose token lasts an hour, and anyone holding it gets in with no further check, the property the bearer token standard describes.

The Solari API key stays in the orchestrator, never inside the sandbox, and a Git token passed to a push travels with that single command, never in the URL or .git/config. With access contained, what remains is making sure the machine does not outlive its job.

End Every Run With a Clean Machine

A sandbox that ran untrusted code should not wait around for the next task. At create time, idleTimeoutMs sets the idle window, and lifecycle: { onTimeout: "kill" } deletes the machine at the end of it instead of the default pause, which keeps the run's state.

Polling a sandbox's status no longer resets its idle timer, so monitoring will not keep it alive. Agents that reuse a warm machine can snapshot a clean state and revert after each run, as the snapshots reference and the guide to isolating untrusted agent code describe.

Choosing the Right Setup

Secure code execution comes down to a rule: the model's code is a stranger's input, so it gets a machine with nothing to steal, a path with no shell and a result that is checked before it is trusted. In practice that is a hardened sandbox, a script run as a file argument, flags read on every call and identifiers kept out of logs. When the same agent also needs the web, the Solari introduction shows how sandboxes, browsers and desktops share one account and one API.

Get Started With Solari

Start by creating a hardened sandbox, writing a test script from the model into it and checking timedOut on the result. Solari is built for this job: sandboxes are ready in 90 ms, and Solari is almost 3x cheaper than E2B per sandbox hour on the pricing page. Create a free Solari account and the Free plan covers the first runs with $3 of monthly credits.

Share this article

Give every agent
a place to work

Browsers, sandboxes and desktops from one API. Start free and scale when you need to.

Planet horizon at sunrise
opsra logo

The Fastest AI Infrastructure

Unsubscribe anytime. See our Privacy Policy.

Copyright © 2026 Solari

Engineered by Pinetree

opsra logo

The Fastest AI Infrastructure

Unsubscribe anytime. See our Privacy Policy.

Copyright © 2026 Solari

Engineered by Pinetree

opsra logo

The Fastest AI Infrastructure

Unsubscribe anytime. See our Privacy Policy.

Copyright © 2026 Solari

Engineered by Pinetree