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

See [Secrets](/sandboxes/secrets) for how placeholder substitution works and usage examples.

Secrets never enter the VM. The Go SDK passes each [`SecretEntry`](#secretentrystruct) to the runtime, which exposes a placeholder string inside the guest (e.g. `$MSB_SERVICE_API_KEY`) and substitutes the real value at the network layer only when traffic reaches an allowed host.

<div className="msb-glance">

  <p className="msb-gl"><span className="msb-dot static"></span>Functions<span className="msb-ct">1</span></p>
  <a className="msb-row" href="#withsecrets"><span className="msb-rn">WithSecrets()</span><span className="msb-rg">attach secrets to a sandbox</span></a>

  <p className="msb-gl"><span className="msb-dot instance"></span>Methods · 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">build a SecretEntry from an env var</span></a>

  <p className="msb-gl"><span className="msb-dot type"></span>Types</p>
  <div className="msb-chiprow">
    <a className="msb-typepill" href="#secretentrystruct">SecretEntry</a>
    <a className="msb-typepill" href="#secretenvoptionsstruct">SecretEnvOptions</a>
    <a className="msb-typepill" href="#violationactionstring-enum">ViolationAction</a>
  </div>

</div>

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

```go
import m "github.com/superradcompany/microsandbox/sdk/go"

sb, err := m.CreateSandbox(ctx, "worker",
    m.WithImage("python:3.12"),
    m.WithSecrets(m.Secret.Env(
        "SERVICE_API_KEY",
        os.Getenv("SERVICE_API_KEY"),
        m.SecretEnvOptions{
            AllowHosts: []string{"api.example.com"},
        },
    )),
)
```

## Host matching

Go does not expose the Rust `HostPattern` enum directly. Exact and wildcard host patterns are represented with the `AllowHosts` and `AllowHostPatterns` fields on [`SecretEntry`](#secretentrystruct) and [`SecretEnvOptions`](#secretenvoptionsstruct).

| Runtime pattern | Go API | Matches |
|-----------------|--------|---------|
| `HostPattern::Exact("api.example.com")` | `AllowHosts: []string{"api.example.com"}` | That exact SNI host |
| `HostPattern::Wildcard("*.example.com")` | `AllowHostPatterns: []string{"*.example.com"}` | Hosts matching the wildcard pattern |

These fields decide where the real secret value may be substituted. A host that is not matched by either field is disallowed for that secret, so sending its placeholder there triggers the configured [`ViolationAction`](#violationactionstring-enum). Allow-list entries are pinned to observed DNS answers and TLS identity. At least one exact or wildcard host is required.

## Functions

---

#### <span className="msb-hn">WithSecrets()</span>
<div className="msb-tags"><span className="msb-tag is-static">func</span></div>

```go
func WithSecrets(secrets ...SecretEntry) SandboxOption
```

Append credential secrets to the sandbox. Each call appends, so multiple calls accumulate. Secrets never enter the VM; the network proxy substitutes them at the transport layer. Pass to [`CreateSandbox`](/sdk/go/sandbox#createsandbox) alongside the other options.

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

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>secrets</code><a className="msb-type" href="#secretentrystruct">...SecretEntry</a></div>
    <div className="msb-param-desc">Secret entries to attach, usually built with <a className="msb-type" href="#secret-env">Secret.Env</a>.</div>
  </div>
</div>

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

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">SandboxOption</span></div>
    <div className="msb-param-desc">Functional option for <a className="msb-type" href="/sdk/go/sandbox#createsandbox">CreateSandbox</a>.</div>
  </div>
</div>

<Accordion title="Example">

```go
sb, err := m.CreateSandbox(ctx, "worker",
    m.WithImage("python:3.12"),
    m.WithSecrets(
        m.Secret.Env("STRIPE_KEY", os.Getenv("STRIPE_KEY"),
            m.SecretEnvOptions{AllowHosts: []string{"api.stripe.com"}}),
        m.Secret.Env("OPENAI_API_KEY", os.Getenv("OPENAI_API_KEY"),
            m.SecretEnvOptions{AllowHostPatterns: []string{"*.openai.com"}}),
    ),
)
```

</Accordion>

## Methods

The [`Secret`](#secret-env) factory is a package-level value. Call its methods to build [`SecretEntry`](#secretentrystruct) values without populating struct literals by hand.

---

#### <span className="msb-recv">Secret.</span><span className="msb-hn">Env()</span>
<div className="msb-tags"><span className="msb-tag is-instance">method</span></div>

```go
func (secretFactory) Env(envVar, value string, opts SecretEnvOptions) SecretEntry
```

Build a [`SecretEntry`](#secretentrystruct) that maps an environment variable to a real value. The guest sees a placeholder; the real value is substituted by the TLS proxy only when traffic goes to an allowed host. Pass an empty [`SecretEnvOptions`](#secretenvoptionsstruct)`{}` when no extra tuning is needed.

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

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>envVar</code><span className="msb-type">string</span></div>
    <div className="msb-param-desc">Environment variable name holding the placeholder inside the sandbox. 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">string</span></div>
    <div className="msb-param-desc">The real secret value. Never crosses the FFI into the guest.</div>
  </div>
  <div className="msb-param">
    <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#secretenvoptionsstruct">SecretEnvOptions</a></div>
    <div className="msb-param-desc">Allowed hosts, placeholder override, TLS requirement, and violation action.</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="#secretentrystruct">SecretEntry</a></div>
    <div className="msb-param-desc">Pass to <a className="msb-type" href="#withsecrets">WithSecrets</a>.</div>
  </div>
</div>

<Accordion title="Example">

```go
m.Secret.Env("STRIPE_KEY", os.Getenv("STRIPE_KEY"),
    m.SecretEnvOptions{
        AllowHosts:        []string{"api.stripe.com"},
        AllowHostPatterns: []string{"*.stripe.com"},
        Placeholder:       "$MSB_STRIPE",
    },
)
```

</Accordion>

## Types

---

### SecretEntry<span className="msb-tag is-type" style={{marginLeft: "8px"}}>struct</span>

<p className="msb-backref">accepted by <a href="#withsecrets">WithSecrets()</a> · returned by <a href="#secret-env">Secret.Env()</a></p>

A single credential the network proxy substitutes at the transport layer. The value never reaches the guest VM. Usually produced by [`Secret.Env`](#secret-env); exported for callers that prefer struct literals.

| Field | Type | Description |
|-------|------|-------------|
| `EnvVar` | `string` | Environment variable name holding the placeholder inside the sandbox. Must be non-empty and cannot contain `=` or NUL; shell-identifier syntax is not required |
| `Value` | `string` | Real secret value; never crosses the FFI into the guest |
| `AllowHosts` | `[]string` | Hosts allowed to receive the real value (exact match) |
| `AllowHostPatterns` | `[]string` | Wildcard host patterns, e.g. `"*.openai.com"` |
| `Placeholder` | `string` | Custom placeholder shown inside the sandbox in place of the secret. Auto-generated from `EnvVar` when empty. Custom values must be non-empty, at most 1024 bytes, and cannot contain NUL, CR, or LF |
| `RequireTLS` | `*bool` | Require a verified TLS identity before substituting. Defaults to `true` when `nil` |
| `OnViolation` | [`ViolationAction`](#violationactionstring-enum) | Override the sandbox-wide action when this secret is detected going to a disallowed host. The last non-empty value across all secrets wins, since the runtime applies it network-wide |

---

### SecretEnvOptions<span className="msb-tag is-type" style={{marginLeft: "8px"}}>struct</span>

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

Tunes [`Secret.Env`](#secret-env) beyond the required `envVar` and `value`.

| Field | Type | Description |
|-------|------|-------------|
| `AllowHosts` | `[]string` | Allowed hosts (exact match) |
| `AllowHostPatterns` | `[]string` | Wildcard host patterns |
| `Placeholder` | `string` | Custom placeholder: non-empty, up to 1024 bytes, no NUL/CR/LF |
| `RequireTLS` | `*bool` | Require a verified TLS identity before substituting. Defaults to `true` when `nil` |
| `OnViolation` | [`ViolationAction`](#violationactionstring-enum) | Per-secret violation action |

---

### ViolationAction<span className="msb-tag is-type" style={{marginLeft: "8px"}}>string enum</span>

<p className="msb-backref">field of <a href="#secretentrystruct">SecretEntry</a> · <a href="/sdk/go/networking#networkconfig">NetworkConfig</a></p>

```go
type ViolationAction string
```

What happens when a secret placeholder is detected going to a host the secret isn't allowed to talk to. Configure the sandbox-wide default on [`NetworkConfig.OnSecretViolation`](/sdk/go/networking#networkconfig); override per-secret with [`SecretEntry.OnViolation`](#secretentrystruct).

| Constant | Value | Description |
|----------|-------|-------------|
| `ViolationActionDefault` | `""` | Leave the runtime default in place (currently `block-and-log`) |
| `ViolationActionBlock` | `"block"` | Silently drop the request. The guest sees a connection reset |
| `ViolationActionBlockAndLog` | `"block-and-log"` | Drop the request and emit a warning log on the host side |
| `ViolationActionBlockAndTerminate` | `"block-and-terminate"` | Drop the request, log an error, and shut down the entire sandbox |
