---
title: Secrets
description: Python SDK - Secret injection API reference
---

Bind a credential to an environment variable so the guest only ever sees a placeholder: the real value is substituted by the TLS proxy when traffic reaches an allowed host, and blocked everywhere else. See [Secrets](/sandboxes/secrets) for how placeholder substitution works and usage examples.

<div className="msb-glance">

  <p className="msb-gl"><span className="msb-dot static"></span>Factory · Secret<span className="msb-ct">1</span></p>
  <a className="msb-row" href="#secret-env"><span className="msb-rn">Secret.env()</span><span className="msb-rg">map an env var to a secret value</span></a>

  <p className="msb-gl"><span className="msb-dot static"></span>Violation policy · ViolationPolicy<span className="msb-ct">4</span></p>
  <a className="msb-row" href="#violationpolicy-block"><span className="msb-rn">ViolationPolicy.block()</span><span className="msb-rg">silently drop on violation</span></a>
  <a className="msb-row" href="#violationpolicy-block_and_log"><span className="msb-rn">ViolationPolicy.block_and_log()</span><span className="msb-rg">drop and warn</span></a>
  <a className="msb-row" href="#violationpolicy-block_and_terminate"><span className="msb-rn">ViolationPolicy.block_and_terminate()</span><span className="msb-rg">drop, log, shut down</span></a>
  <a className="msb-row" href="#violationpolicy-passthrough"><span className="msb-rn">ViolationPolicy.passthrough()</span><span className="msb-rg">forward placeholder to hosts</span></a>

  <p className="msb-gl"><span className="msb-dot type"></span>Types</p>
  <div className="msb-chiprow">
    <a className="msb-typepill" href="#secretentry">SecretEntry</a>
    <a className="msb-typepill" href="#secretinjection">SecretInjection</a>
    <a className="msb-typepill" href="#violationaction">ViolationAction</a>
    <a className="msb-typepill" href="#violationpolicy">ViolationPolicy</a>
    <a className="msb-typepill" href="#secretviolationerror">SecretViolationError</a>
  </div>

</div>

<p className="msb-label" id="typical-flow">Typical flow</p>

```python
import os
from microsandbox import Sandbox, Secret

sb = await Sandbox.create(
    "worker",
    image="python",
    secrets=[
        Secret.env(
            "GITHUB_TOKEN",
            value=os.environ["GITHUB_TOKEN"],
            allow_hosts=["api.github.com"],
            allow_host_patterns=["*.githubusercontent.com"],
        ),
    ],
)
```

## Factory methods

---

#### <span className="msb-recv">Secret.</span><span className="msb-hn">env()</span>
<div className="msb-tags"><span className="msb-tag is-static">staticmethod</span></div>

```python
@staticmethod
def env(
    env_var: str,
    *,
    value: str,
    allow_hosts: Sequence[str] = (),
    allow_host_patterns: Sequence[str] = (),
    placeholder: str | None = None,
    require_tls: bool = True,
    on_violation: ViolationAction | ViolationPolicy = ViolationAction.BLOCK_AND_LOG,
    injection: SecretInjection | None = None,
) -> SecretEntry
```

Create a secret entry that maps an environment variable to a real value. The guest sees a placeholder; the real value is only substituted by the TLS proxy when traffic goes to an allowed host. Pass the returned entry to `Sandbox.create(..., secrets=[...])`.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>env_var</code><span className="msb-type">str</span></div>
    <div className="msb-param-desc">Environment variable name. Must be non-empty and cannot contain <code>=</code> or NUL; shell-identifier syntax is not required.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>value</code><span className="msb-type">str</span></div>
    <div className="msb-param-desc">The real secret value. Never enters the guest VM. Keyword-only and required.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>allow_hosts</code><span className="msb-type">Sequence[str]</span></div>
    <div className="msb-param-desc">Hosts allowed to receive the real value (exact match). At least one exact or wildcard host is required. Default <code>()</code>.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>allow_host_patterns</code><span className="msb-type">Sequence[str]</span></div>
    <div className="msb-param-desc">Wildcard host patterns, e.g. <code>"*.googleapis.com"</code>. Default <code>()</code>.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>placeholder</code><span className="msb-type">str | None</span></div>
    <div className="msb-param-desc">Custom placeholder string: non-empty, up to 1024 bytes, no NUL/CR/LF. Auto-generated as <code>$MSB_&lt;env_var&gt;</code> when <code>None</code>. Default <code>None</code>.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>require_tls</code><span className="msb-type">bool</span></div>
    <div className="msb-param-desc">Only substitute on TLS-intercepted connections. Disable only if you know the traffic is safe. Default <code>True</code>.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>on_violation</code><a className="msb-type" href="#violationaction">ViolationAction</a> | <a className="msb-type" href="#violationpolicy">ViolationPolicy</a></div>
    <div className="msb-param-desc">Per-secret violation behavior. Default <code>ViolationAction.BLOCK_AND_LOG</code>.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>injection</code><a className="msb-type" href="#secretinjection">SecretInjection</a> | None</div>
    <div className="msb-param-desc">Where in the HTTP request to substitute. <code>None</code> uses <code>SecretInjection()</code> defaults. Default <code>None</code>.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#secretentry">SecretEntry</a></div>
    <div className="msb-param-desc">Secret entry for <code>Sandbox.create(secrets=[...])</code>.</div>
  </div>
</div>

<Accordion title="Example">

```python
from microsandbox import Secret, SecretInjection

secret = Secret.env(
    "SERVICE_API_KEY",
    value=os.environ["SERVICE_API_KEY"],
    allow_hosts=["api.example.com"],
    injection=SecretInjection(query_params=True),
)
```

</Accordion>

---

## Violation policy

`on_violation` (per secret) and `Network.on_secret_violation` (sandbox-wide default) both accept a bare [`ViolationAction`](#violationaction) or a [`ViolationPolicy`](#violationpolicy). The classmethods below construct a policy. Use [`passthrough()`](#violationpolicy-passthrough) when selected hosts should receive the placeholder unchanged; the other three mirror the plain [`ViolationAction`](#violationaction) values.

---

#### <span className="msb-recv">ViolationPolicy.</span><span className="msb-hn">block()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def block(cls) -> ViolationPolicy
```

Silently drop the request when the placeholder is sent to a disallowed host. The guest sees a connection reset. Equivalent to `ViolationAction.BLOCK`.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#violationpolicy">ViolationPolicy</a></div>
    <div className="msb-param-desc">Policy with <code>fallback = ViolationAction.BLOCK</code>.</div>
  </div>
</div>

---

#### <span className="msb-recv">ViolationPolicy.</span><span className="msb-hn">block_and_log()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def block_and_log(cls) -> ViolationPolicy
```

Drop the request and emit a warning log on the host side. This is the default. Equivalent to `ViolationAction.BLOCK_AND_LOG`.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#violationpolicy">ViolationPolicy</a></div>
    <div className="msb-param-desc">Policy with <code>fallback = ViolationAction.BLOCK_AND_LOG</code>.</div>
  </div>
</div>

---

#### <span className="msb-recv">ViolationPolicy.</span><span className="msb-hn">block_and_terminate()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def block_and_terminate(cls) -> ViolationPolicy
```

Drop the request, log an error, and shut down the entire sandbox. Equivalent to `ViolationAction.BLOCK_AND_TERMINATE`.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#violationpolicy">ViolationPolicy</a></div>
    <div className="msb-param-desc">Policy with <code>fallback = ViolationAction.BLOCK_AND_TERMINATE</code>.</div>
  </div>
</div>

---

#### <span className="msb-recv">ViolationPolicy.</span><span className="msb-hn">passthrough()</span>
<div className="msb-tags"><span className="msb-tag is-static">classmethod</span></div>

```python
@classmethod
def passthrough(
    cls,
    *,
    hosts: Sequence[str] = (),
    host_patterns: Sequence[str] = (),
    all_hosts: bool = False,
) -> ViolationPolicy
```

Forward the placeholder unchanged to matching hosts instead of blocking. Passthrough hosts do **not** make a secret eligible for substitution; they only prevent blocking when the guest sends the placeholder to a matching host, so the request is forwarded with the placeholder intact. Hosts outside the passthrough set fall back to `BLOCK_AND_LOG`.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>hosts</code><span className="msb-type">Sequence[str]</span></div>
    <div className="msb-param-desc">Exact hosts that may receive the placeholder unchanged. Keyword-only. Default <code>()</code>.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>host_patterns</code><span className="msb-type">Sequence[str]</span></div>
    <div className="msb-param-desc">Wildcard host patterns, e.g. <code>"*.example.com"</code>. Keyword-only. Default <code>()</code>.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>all_hosts</code><span className="msb-type">bool</span></div>
    <div className="msb-param-desc">Forward the placeholder unchanged to every host. Keyword-only. Default <code>False</code>.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#violationpolicy">ViolationPolicy</a></div>
    <div className="msb-param-desc">Passthrough policy.</div>
  </div>
</div>

<Accordion title="Example">

```python
from microsandbox import Secret, ViolationPolicy

secret = Secret.env(
    "API_KEY",
    value=os.environ["API_KEY"],
    allow_hosts=["api.github.com"],
    on_violation=ViolationPolicy.passthrough(
        hosts=["api.anthropic.com"],
        host_patterns=["*.anthropic.com"],
    ),
)
```

</Accordion>

---

## Types

### SecretEntry

<div className="msb-tags"><span className="msb-tag is-type">frozen dataclass</span></div>

<p className="msb-backref">Returned by <a href="#secret-env">Secret.env()</a></p>

A single secret entry, used in `Sandbox.create(secrets=[...])`. Construct it with [`Secret.env()`](#secret-env) rather than directly.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| env_var | `str` | required | Environment variable name (non-empty, no `=` or NUL) |
| value | `str` | required | Secret value. Never enters the guest |
| allow_hosts | `tuple[str, ...]` | `()` | Allowed hosts (exact match) |
| allow_host_patterns | `tuple[str, ...]` | `()` | Wildcard patterns |
| placeholder | `str \| None` | `None` | Placeholder string: non-empty, up to 1024 bytes, no NUL/CR/LF. Auto-generated as `$MSB_<env_var>` when `None` |
| require_tls | `bool` | `True` | Only substitute on TLS-intercepted connections |
| on_violation | [`ViolationAction`](#violationaction) `\|` [`ViolationPolicy`](#violationpolicy) | `BLOCK_AND_LOG` | Per-secret violation behavior |
| injection | [`SecretInjection`](#secretinjection) | `SecretInjection()` | Per-request injection scopes |

### SecretInjection

<div className="msb-tags"><span className="msb-tag is-type">frozen dataclass</span></div>

<p className="msb-backref">Used by <a href="#secret-env">Secret.env()</a> · <a href="#secretentry">SecretEntry.injection</a></p>

Controls where in the HTTP request the secret value can be substituted.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| headers | `bool` | `True` | Substitute the placeholder anywhere it appears in the headers. |
| basic_auth | `bool` | `True` | Decode `Authorization: Basic <base64>` credentials, substitute the placeholder in the decoded `user:password`, and re-encode. Other schemes (`Bearer`, `Digest`) are handled by `headers`. |
| query_params | `bool` | `False` | Substitute in the request line's query string. |
| body | `bool` | `False` | Substitute in request bodies when microsandbox can inspect and rewrite them safely. Encoded bodies are forwarded unchanged, and body placeholders in unsupported body formats are blocked instead of being leaked. |

### ViolationAction

<div className="msb-tags"><span className="msb-tag is-type">StrEnum</span></div>

<p className="msb-backref">Used by <a href="#secret-env">Secret.env()</a> · <a href="#secretentry">SecretEntry.on_violation</a></p>

String enum ([`StrEnum`](https://docs.python.org/3/library/enum.html#enum.StrEnum)) defining the action taken when a secret placeholder is sent to a disallowed host.

| Member | Value | Description |
|--------|-------|-------------|
| `BLOCK` | `"block"` | Silently drop the request. The guest sees a connection reset. |
| `BLOCK_AND_LOG` | `"block-and-log"` | Drop the request and emit a warning log on the host side. This is the default. |
| `BLOCK_AND_TERMINATE` | `"block-and-terminate"` | Drop the request, log an error, and shut down the entire sandbox. |
| `PASSTHROUGH` | `"passthrough"` | Forward matching hosts with the placeholder unchanged. Non-matching hosts use the default secret violation action. |

### ViolationPolicy

<div className="msb-tags"><span className="msb-tag is-type">frozen dataclass</span></div>

<p className="msb-backref">Used by <a href="#secret-env">Secret.env()</a> · <a href="#secretentry">SecretEntry.on_violation</a></p>

Secret violation behavior, including optional passthrough hosts. Construct it with the classmethods ([`block()`](#violationpolicy-block), [`block_and_log()`](#violationpolicy-block_and_log), [`block_and_terminate()`](#violationpolicy-block_and_terminate), [`passthrough()`](#violationpolicy-passthrough)) rather than setting fields directly.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| fallback | [`ViolationAction`](#violationaction) | `BLOCK_AND_LOG` | Action for hosts not covered by the passthrough set |
| passthrough_hosts | `tuple[str, ...]` | `()` | Exact hosts forwarded with the placeholder unchanged |
| passthrough_host_patterns | `tuple[str, ...]` | `()` | Wildcard patterns forwarded with the placeholder unchanged |
| passthrough_all_hosts | `bool` | `False` | Forward the placeholder unchanged to every host |

### SecretViolationError

<div className="msb-tags"><span className="msb-tag is-type">exception</span></div>

<p className="msb-backref">Subclass of <code>MicrosandboxError</code></p>

Raised when a secret placeholder was sent to a disallowed host. Carries `code = "secret-violation"`.
