How to clone a private Git repository into a sandbox without exposing the token
Store the token as a Runtime secret that adds git's Authorization header, then clone and push over HTTPS; on paid accounts SSH works too.
On Runtime the token never enters the sandbox. A secret is sealed when you store it, and the host's proxy adds it to HTTPS requests bound for the hosts you name. The sandbox holds a worthless placeholder, so an agent that prints its environment, or a prompt injection that tries to send the token elsewhere, has nothing to leak. git is in every sandbox; Ubuntu 24.04's package is git 2.43.0, checked 25 September 2026.
Clone over HTTPS with a header secret
GitHub accepts a token over HTTPS as HTTP Basic credentials with the user name
x-access-token, the form GitHub's own actions/checkout sends. Store that
credential once, base64-encoded, as a secret whose header is Authorization:
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();const token = process.env.GITHUB_TOKEN ?? ""; // a fine-grained token for the repositories the agent needsawait runtime.secrets.set("GIT_GITHUB_AUTH", { value: Buffer.from(`x-access-token:${token}`).toString("base64"), hosts: ["github.com"], header: "Authorization", format: "Basic {value}",});await using sbx = await runtime.sandboxes.create();await sbx.exec("git clone --depth 1 https://github.com/acme/private-app.git app", { check: true, timeoutMs: 300_000,});Pythonimport base64import osfrom withruntime import Runtimeruntime = Runtime()token = os.environ["GITHUB_TOKEN"]runtime.secrets.set( "GIT_GITHUB_AUTH", value=base64.b64encode(f"x-access-token:{token}".encode()).decode(), hosts=["github.com"], header="Authorization", format="Basic {value}",)with runtime.sandboxes.create() as sbx: sbx.exec("git clone --depth 1 https://github.com/acme/private-app.git app", check=True, timeout_ms=300_000)The URL carries no credentials. With header, the proxy sets that header on
every HTTPS request to github.com and replaces any the sandbox sent, so git
needs no credential helper and never prompts. The secret applies to every
sandbox of the account from then on; replacing it keeps working sandboxes up
to date within seconds.
This works on the free trial, which reaches ports 80 and 443.
Commit and push the agent's work
Push goes to the same host, so the same secret covers it. Set an identity for the commit, work on a branch, and push:
TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.connect(process.env.SANDBOX_ID ?? "");const git = (args: string) => sbx.exec(`git -C /workspace/app ${args}`, { check: true, timeoutMs: 120_000 });await git("config user.name 'Build Agent'");await git("config user.email 'agent@example.com'");await git("switch -c agent/fix-login");await git("add -A");await git("commit -m 'Fix the login redirect'");await git("push -u origin agent/fix-login");Scope the token to what the agent should do. A fine-grained GitHub token can
be limited to chosen repositories with only "Contents" read and write; a
branch protection rule on main then keeps the agent to branches and pull
requests. To open the pull request, see the GitHub CLI in a sandbox.
Which way to authenticate
| Method | Trial | Paid | Where the credential lives | Notes |
|---|---|---|---|---|
| HTTPS with a header secret | Yes | Yes | Sealed on Runtime's servers | The method above |
| HTTPS, token in the URL | Yes | Yes | In the sandbox, in .git/config |
Avoid: any code in the sandbox can read it |
| SSH with a deploy key | No | Yes | In the sandbox, in ~/.ssh |
Port 22; one repository per key |
| Public repository | Yes | Yes | None | git clone https://... as is |
GitLab, Bitbucket and a self-hosted server work the same way over HTTPS: put
their host in hosts and the credential their HTTPS git endpoint expects in
the value.
SSH on a paid account
A paid sandbox reaches any public host on any port, so git@github.com:
URLs work. SSH needs the private key in the sandbox, so use a deploy key: it
belongs to one repository and is read-only unless you allow write access when
you add it.
Pythonimport osfrom withruntime import Sandboxwith Sandbox.create(funding="paid") as sbx: sbx.files.write("/workspace/.ssh/id_ed25519", os.environ["DEPLOY_KEY"], mode=0o600) sbx.exec("git clone git@github.com:acme/private-app.git app", check=True, timeout_ms=300_000, env={"GIT_SSH_COMMAND": "ssh -o StrictHostKeyChecking=accept-new"})accept-new records GitHub's host key on first contact instead of stopping
to ask. If the sandbox has an allow list, add github.com:22 to its
connect rules (the network).
Faster clones for big repositories
| Need | Command |
|---|---|
| The latest commit only | git clone --depth 1 <url> |
| History, but no old file contents | git clone --filter=blob:none <url> |
| One directory of a monorepo | git clone --filter=blob:none --sparse <url>, then git sparse-checkout set <dir> |
The default 4 GiB disk has about 2.5 GiB free; give a large repository more
with diskMiB. To start every sandbox with the repository already there,
clone it once and keep a snapshot; new sandboxes
from the snapshot only need git pull.
Related
- A sandbox for a coding agent
- Open pull requests with the GitHub CLI
- Secrets sandboxes never see
- Run Claude Code in a sandbox
- Egress control
Sources
Checked 25 September 2026.
- actions/checkout, git-auth-helper.ts:
the
AUTHORIZATION: basicheader built fromx-access-token:<token> - Managing deploy keys: one repository per key, read-only by default
- git in Ubuntu noble: 2.43.0
- Managing personal access tokens and fine-grained token permissions: "Only select repositories" and the "Contents" permission
- git clone and
git sparse-checkout:
--depth,--filter,--sparse
Facts on this page were checked on 25 September 2026.