# 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. The host's proxy adds it to HTTPS requests bound for the hosts you name. The sandbox holds a placeholder that is worthless on its own. 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 October 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`. This is the form that GitHub's own `actions/checkout` sends. Store that credential once, base64-encoded, as a secret whose header is `Authorization`: ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); const token = process.env.GITHUB_TOKEN ?? ""; // a fine-grained token for the repositories the agent needs await 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, }); ``` ```python check import base64 import os from withruntime import Runtime runtime = 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` set, the proxy sets that header on every HTTPS request to `github.com`. It replaces any header of that name that the sandbox sent. So git needs no credential helper and never prompts. The secret applies to every sandbox in the account from then on. Replacing it updates running sandboxes within seconds. This works without credit. A sandbox without credit 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: ```ts check import { 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 the "Contents" read and write permission. 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](/integrations/github-cli). ## Which way to authenticate | Method | Without credit | 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 put the credential that 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 inside the sandbox. So use a deploy key. A deploy key belongs to one repository. It is read-only unless you allow write access when you add it. ```python check import os from withruntime import Sandbox with Sandbox.create() 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. Without it, SSH stops to ask. If the sandbox has an allow list, add `github.com:22` to its `connect` rules ([the network](/docs/sandbox-environment#the-network)). ## Faster clones for big repositories | Need | Command | | --------------------------------- | ----------------------------------------------------------------------------------- | | The latest commit only | `git clone --depth 1 ` | | History, but no old file contents | `git clone --filter=blob:none ` | | One directory of a monorepo | `git clone --filter=blob:none --sparse `, then `git sparse-checkout set ` | The default 4 GiB disk has about 2.5 GiB free. Give a large repository more space with `diskMiB`. To start every sandbox with the repository already there, clone it once and keep a [snapshot](/glossary/sandbox-snapshot). New sandboxes made from the snapshot need only `git pull`. ## Related - [A sandbox for a coding agent](/use-cases/coding-agent-sandbox) - [Open pull requests with the GitHub CLI](/integrations/github-cli) - [Secrets sandboxes never see](/docs/security#secrets-sandboxes-never-see) - [Run Claude Code in a sandbox](/integrations/claude-code) - [Egress control](/glossary/egress-control) ## Sources Checked 25 October 2026. - [actions/checkout, git-auth-helper.ts](https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts): the `AUTHORIZATION: basic` header built from `x-access-token:` - [Managing deploy keys](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys): one repository per key, read-only by default - [git in Ubuntu noble](https://packages.ubuntu.com/noble/git): 2.43.0 - [Managing personal access tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) and [fine-grained token permissions](https://docs.github.com/en/rest/authentication/permissions-required-for-fine-grained-personal-access-tokens): "Only select repositories" and the "Contents" permission - [git clone](https://git-scm.com/docs/git-clone) and [git sparse-checkout](https://git-scm.com/docs/git-sparse-checkout): `--depth`, `--filter`, `--sparse` Facts on this page were checked on 25 October 2026.