---
title: Secrets
description: Python SDK - Secret substitution API reference
keywords: ["Python SDK", "Python secrets", "microsandbox secrets"]
---

Configure secret substitution for outbound requests. See [Secrets](/sandboxes/secrets) for usage and security concepts.

## Secret

#### <span className="msb-recv">Secret.</span><span className="msb-hn">env()</span>

```python
@staticmethod
def env(
    env_var: str,
    *,
    value: str,
    allow: Sequence[str] = (),
    allow_placeholder_for: Sequence[str] = (),
    passthrough: Sequence[str] = (),  # deprecated alias
    placeholder: str | None = None,
    require_tls_identity: bool = True,
    violation_action: ViolationAction | None = None,
    substitution: SecretSubstitution | None = None,
) -> SecretEntry
```

<Accordion title="Example">

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

secret = Secret.env(
    "SERVICE_API_KEY",
    value=os.environ["SERVICE_API_KEY"],
    allow=["api.example.com", "*.example.com"],
    allow_placeholder_for=["api.anthropic.com"],
    violation_action=ViolationAction.BLOCK_AND_TERMINATE,
    substitution=SecretSubstitution(query=True),
)

sb = await Sandbox.create(
    "worker",
    image="python",
    secrets=[secret],
    secret_violation_action=ViolationAction.BLOCK_AND_LOG,
)
```

</Accordion>

Create a secret entry that maps an environment variable to a real value. The guest sees a placeholder; the TLS proxy substitutes the real value only 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. Raw values are persisted in the durable sandbox configuration.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>allow</code><span className="msb-type">Sequence[str]</span></div>
    <div className="msb-param-desc">Exact hosts or wildcard patterns allowed to receive the real value. 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_placeholder_for</code><span className="msb-type">Sequence[str]</span></div>
    <div className="msb-param-desc">Exact hosts or wildcard patterns allowed to receive the unchanged placeholder. Does not grant access to the real value. 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_identity</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>violation_action</code><a className="msb-type" href="#violationaction">ViolationAction</a> | None</div>
    <div className="msb-param-desc">Per-secret blocking action. Default <code>None</code> inherits the network setting, whose default is <code>BLOCK_AND_LOG</code>.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>substitution</code><a className="msb-type" href="#secretsubstitution">SecretSubstitution</a> | None</div>
    <div className="msb-param-desc">Where in the HTTP request to substitute. <code>None</code> uses <code>SecretSubstitution()</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>

## Validation and lifecycle

Sandbox configuration validation rejects empty environment names, names containing `=` or NUL, missing allowed hosts, every substitution location disabled, and placeholders that are empty, longer than 1024 bytes, or contain NUL/CR/LF. `Secret.env()` constructs an entry; it does not itself run all native validation.

Raw values are persisted at rest. Prefer source references through [live modification](/sandboxes/secrets#update-secrets) when the secret is available in the host environment. Rotating or removing an existing secret does not require a restart; adding a secret or changing its guest-visible placeholder does. Live modification is local-only.

`passthrough=` remains a deprecated alias for `allow_placeholder_for=` and emits a `DeprecationWarning` when used with hosts. If both are supplied, the host lists are combined. The returned `SecretEntry.passthrough` field and serialized configuration keep their existing names.

## Types

### SecretEntry

<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 | `tuple[str, ...]` | `()` | Exact or wildcard hosts allowed to receive the real value |
| passthrough | `tuple[str, ...]` | `()` | Exact or wildcard hosts allowed to receive the unchanged placeholder |
| 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_identity | `bool` | `True` | Only substitute on TLS-intercepted connections |
| violation_action | [`ViolationAction`](#violationaction) `\| None` | `None` | Per-secret override; inherits the sandbox-wide action when omitted |
| substitution | [`SecretSubstitution`](#secretsubstitution) | `SecretSubstitution()` | Per-request substitution scopes |

### SecretSubstitution

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

Frozen dataclass selecting where in an HTTP request the real value may replace the placeholder. At least one location must remain enabled. On credential-allowed hosts that pass the secret's identity checks, disabled locations forward the placeholder unchanged. Other destinations must match `passthrough` or follow the violation action.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| headers | `bool` | `True` | Substitute in headers, including decoded and re-encoded Basic authentication. |
| query | `bool` | `False` | Substitute in the request URL query string. |
| body | `bool` | `False` | Substitute in supported HTTP/1 bodies. |

When body substitution is enabled, fixed-length HTTP/1 bodies up to 16 MiB are rewritten with an updated `Content-Length`; larger fixed-length bodies are blocked. Chunked HTTP/1 bodies are decoded and re-encoded. Encoded bodies pass through unchanged. HTTP/2 DATA-frame body substitution is unsupported, and matching body placeholders are blocked.

Default settings are omitted from serialized configuration; explicitly setting `headers=False` is preserved. Passing a value other than `SecretSubstitution` to `SecretEntry.substitution` raises `TypeError` when serialized.

### ViolationAction

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

String enum defining the blocking action when a placeholder cannot be substituted or passed through. Set the sandbox-wide default with `Network.secret_violation_action` or the top-level `Sandbox.create(secret_violation_action=...)`; the top-level value takes precedence if both are supplied. A secret's `violation_action` overrides that default. Passthrough is a host policy, not an enum member.

| Member | Value | Description |
|--------|-------|-------------|
| `ViolationAction.BLOCK` | `"block"` | Silently drop the request. The guest sees a connection reset. |
| `ViolationAction.BLOCK_AND_LOG` | `"block-and-log"` | Drop the request and emit a warning log on the host side. This is the default. |
| `ViolationAction.BLOCK_AND_TERMINATE` | `"block-and-terminate"` | Drop the request, log an error, and shut down the entire sandbox. |

### SecretViolationError

<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"`.
