Mehdi Akiki
Published on

AI Agent Sandbox Permissions: A Deno Sandbox Checklist

Authors
  • Mehdi Akiki avatar
    Name
    Mehdi Akiki
    Twitter

Reference · Through the layers

An agent needs to read a CSV and calculate a total. You put its code in a separate VM. Good. Now ask what that VM can reach.

Can it call the internet? Is there a real API key in its environment? Did you mount a directory containing files from another job? These questions matter even if the code never escapes the VM.

For this example, assume the agent handles a private customer file. It needs that file and a small output directory. It does not need your source repository, cloud credentials, or general internet access. That gives us a specific policy to check.

Read the defaults before setting the options

The word “sandbox” doesn't tell you the network policy. Deno Sandbox's security documentation says outbound access is unrestricted when allowNet is omitted. Supplying the option restricts destinations to the listed hosts.

That is easy to miss. A separate VM can still have a wide-open network path.

Here are four configurations to compare. The table describes the documented policy, not results collected from a running deployment:

allowNet valueRequest to reports.example:443Request to reports.example:8443Request to another host
Option omittedAllowed by the network policyAllowed by the network policyAllowed by the network policy
[]BlockedBlockedBlocked
["reports.example"]AllowedAllowedBlocked
["reports.example:443"]AllowedBlockedBlocked

The example host is illustrative. An allowed operation can still fail because the service is unavailable, a certificate is wrong, or its own authorization rejects the request. “Allowed” here only describes this network rule.

For an offline calculation, the SDK configuration can make the intended restriction explicit:

import { Sandbox } from "@deno/sandbox";

await using sandbox = await Sandbox.create({
  allowNet: [],
});

An empty allowNet list blocks outbound requests. File uploads, resource limits, and application permissions need their own settings. Use the exact SDK version your project pins and check this configuration in the environment you will actually run. The Deno hosting migration checklist also separates the runtime support period from the service migration.

For a real check, use a harmless endpoint you control on each relevant port, and a second controlled host that must be blocked. Use a fresh sandbox for each configuration, save the SDK version and requested rule, then record whether the call reached the endpoint. A failed HTTP response alone doesn't prove the sandbox denied the connection.

Also check whether package installation needs network access. Preparing dependencies before a customer job starts can avoid granting every job a package-registry route. Keep the dependency image and its update process in the audit; preinstallation moves that work to another place.

Use dummy secrets for the first check

Never test secret handling by asking the agent to print a production key. Give the harness a harmless canary value and check whether untrusted code can read it.

There are two separate questions. Can the program obtain the credential? Can it use an allowed service to do something it should not do?

Deno Sandbox supports secret substitution on requests to approved hosts. That can keep the actual key out of the process. It doesn't automatically restrict every action available through the external API. An allowed host may accept expensive requests or store arbitrary data.

Put limits where the real action happens. For a document conversion service, a trusted handler can accept one conversion operation, a bounded input, and the current tenant's job ID. It shouldn't forward an arbitrary URL, method, and headers just because the agent asked.

Keep the provider credential on that trusted side. The program receives the ability to request one operation, rather than a general key it can reuse elsewhere.

Write down a few things that must fail

I would put these checks in the job's CI verification, using dummy data:

AttemptExpected result
Read the input file assigned to this jobAllowed
Read another job's mounted dataDenied or absent
Contact an unlisted hostBlocked
Read a dummy credential kept on the trusted sideCredential unavailable
Keep running after the job limitStopped
Reopen a finished job using another user's accountRejected by the application

The last row is easy to forget. An environment ID helps find the VM. It doesn't establish who owns it. Every command and file endpoint should check the authenticated user against the application's job record.

Make the failed attempts visible in test output without copying customer data or secrets. The goal is to show which operation was denied, not to collect everything the program tried to read.

Close the paths around the VM

The output is still untrusted. A generated HTML report might contain active scripts. A file can be enormous. A preview URL can accidentally become public.

For the CSV job, accept a small structured result such as a total and a row count. Check its shape and size before showing or storing it. If users need downloadable files, serve them with the right content type and access checks.

Decide what survives the job. Temporary input should disappear when the environment is destroyed. A mounted volume may have a different lifetime, so give it a separate cleanup rule. Don't assume destroying the VM also removed every durable copy.

The earlier guide to sandboxing generated code covers the wider design. If the blocked path involves an outbound broker, rejecting a host before DNS resolution is a separate control to examine. This article's SDK settings do not verify that broker or prove the runtime cannot be escaped.

Start with that and test the denied operations before adding another permission. If a job later needs an external API, you will know which new path you are opening and which checks must change.