openclaw - 💡(How to fix) Fix Allow per-call sandbox env injection from operator-trusted callers [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#80329Fetched 2026-05-11 03:16:06
View on GitHub
Comments
1
Participants
2
Timeline
1
Reactions
2
Timeline (top)
commented ×1

Fix Action

Fix / Workaround

Either way, the values are merged into the agent's tool exec env at process spawn (around src/agents/bash-tools.exec.ts:~1451, where sandboxEnv: sandbox.env is composed). The values are never:

  • Per-call secret injection from external orchestrators. Tokens scoped to a single task, with TTL/revocation managed by the orchestrator.

  • No custom container builds for integrators. The current path forces forking the OpenClaw image just to widen the allowlist for a credentials file — orchestrators end up running their own container indefinitely (which is what we're about to do, see "workaround" below).

  • Clean separation between orchestrator-owned and user-owned secrets. SecretRef stays for static, deployment-time credentials.

  • Generic to any third-party orchestrator. Anything that drives OpenClaw via the OpenAI-compat endpoint can use it.

  • src/gateway/openai-http.ts — read the header(s), validate names against the existing host-env-security predicates, attach to commandInput.

  • src/agents/agent-command.ts — carry through the runtime context.

  • src/agents/bash-tools.exec.ts — merge into the sandbox env at the existing sandboxEnv composition site.

  • src/config/types.openclaw.ts — add the feature flag.

Code Example

x-openclaw-sandbox-env-FOO: bar
x-openclaw-sandbox-env-BAZ: qux

---

x-openclaw-sandbox-env: {"FOO":"bar","BAZ":"qux"}

---

{
  gateway: {
    http: {
      endpoints: {
        chatCompletions: {
          enabled: true,
          allowSandboxEnvHeaders: true,  // off by default
        },
      },
    },
  },
}
RAW_BUFFERClick to expand / collapse

Allow per-call sandbox env injection from operator-trusted callers

Use case

External orchestrators that drive OpenClaw as an agent runtime sometimes need to pass short-lived, scoped credentials into a sandboxed tool exec without the model seeing them.

Concrete example: each skill execution runs in a per-user OpenClaw session. A skill might need a third-party API key that:

  • Is owned by the orchestrator, not the user.
  • Is short-lived (scoped to a single task, with its own TTL and revocation).
  • Must reach the sandbox exec env so a skill script can read it via os.environ.get(...).
  • Must not enter the model's prompt context — the orchestrator can't fully trust user-authored skill code to avoid echoing it back.
  • Must be per-call, not config-time. Each task brings its own credentials.

Survey of existing mechanisms

We did the recon and none of these fit cleanly:

  • SecretRef system (docs/gateway/secrets.md, src/config/types.secrets.ts): config-time, eager-resolved at activation, cached in the runtime snapshot. Resolution is "not lazy on request paths." Not designed for per-call values from external callers.

  • Skills env field (docs/tools/skills-config.md, src/agents/skills/env-overrides.ts): per-skill env map with refcounted activation lifecycle, but values come from static config — not from a per-call source.

  • Custom HTTP headers (x-openclaw-session-key, x-openclaw-model, x-openclaw-message-channel, etc.): the pattern exists for routing and for system-prompt context (e.g. messageChannel reaches the prompt), but no existing header flows data into the sandbox exec env without going through the model.

  • agents.files.set workspace files: the ALLOWED_FILE_NAMES allowlist in src/gateway/server-methods/agents.ts permits exactly 8 markdown files (AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, USER.md, HEARTBEAT.md, BOOTSTRAP.md, MEMORY.md). All of them are loaded into the model's prompt context. So writing a credentials file via this RPC either requires widening the allowlist (fork / custom container) or leaks the credential to the model.

  • /tools/invoke: direct tool invocation by an external caller, not a vehicle for injecting data into a separate session's exec env.

The closest fit is the x-openclaw-* header convention, which we'd like to extend into the sandbox-env destination.

Proposed change

Add a header convention for sandbox env injection from operator-trusted callers. Two viable shapes:

Shape A — per-var headers

x-openclaw-sandbox-env-FOO: bar
x-openclaw-sandbox-env-BAZ: qux

Maps each header to one env var.

Shape B — single JSON header

x-openclaw-sandbox-env: {"FOO":"bar","BAZ":"qux"}

One header carrying a JSON map.

We're not opinionated on which shape (or neither) you'd prefer — happy to defer to maintainer judgment on what fits OpenClaw's conventions best.

Either way, the values are merged into the agent's tool exec env at process spawn (around src/agents/bash-tools.exec.ts:~1451, where sandboxEnv: sandbox.env is composed). The values are never:

  • Written into the model's prompt or system context.
  • Persisted across requests beyond the session's lifetime.
  • Exposed to agents.files.set-allowlisted markdown files.

What this enables

  • Per-call secret injection from external orchestrators. Tokens scoped to a single task, with TTL/revocation managed by the orchestrator.
  • No custom container builds for integrators. The current path forces forking the OpenClaw image just to widen the allowlist for a credentials file — orchestrators end up running their own container indefinitely (which is what we're about to do, see "workaround" below).
  • Clean separation between orchestrator-owned and user-owned secrets. SecretRef stays for static, deployment-time credentials.
  • Generic to any third-party orchestrator. Anything that drives OpenClaw via the OpenAI-compat endpoint can use it.

Security considerations

  • Operator trust is already required to reach /v1/chat/completions (docs/gateway/openai-http-api.md: "Treat this endpoint as a full operator-access surface"). This change doesn't extend the trust boundary.
  • Sandbox env hardening should still apply. Reuse the existing isDangerousHostEnvVarName / isDangerousHostEnvOverrideVarName checks from src/infra/host-env-security.ts. Refuse PATH, LD_PRELOAD, etc.
  • Lifetime is per-request. Don't persist these values in session state across requests; they're re-supplied each call.
  • Logs/redaction. Names log fine; values should redact via the same infrastructure that redacts SecretRef values in snapshots (src/config/redact-snapshot.secret-ref.ts).
  • Skills that dump env are still a risk. A malicious or buggy skill script can env > stdout regardless of how the value got into env. That's the orchestrator's problem to bound (sandbox the skill, audit outputs, etc.) — not something OpenClaw can prevent at the env layer.

Opt-in

A new feature flag, off by default:

{
  gateway: {
    http: {
      endpoints: {
        chatCompletions: {
          enabled: true,
          allowSandboxEnvHeaders: true,  // off by default
        },
      },
    },
  },
}

Existing deployments see no behavior change. Operators that own their gateway and want this functionality flip it on.

Implementation sketch

Roughly 30-50 LOC across:

  • src/gateway/openai-http.ts — read the header(s), validate names against the existing host-env-security predicates, attach to commandInput.
  • src/agents/agent-command.ts — carry through the runtime context.
  • src/agents/bash-tools.exec.ts — merge into the sandbox env at the existing sandboxEnv composition site.
  • src/config/types.openclaw.ts — add the feature flag.

Plus tests at src/gateway/openai-http.test.ts and a doc note at docs/gateway/openai-http-api.md.

Workaround we're using meanwhile

We're widening ALLOWED_FILE_NAMES in a fork to permit credentials.json and fetch-secret.sh. This works but commits us to building and running a custom OpenClaw container indefinitely, which is fragile (we re-build every time we want to track upstream releases, and future allowlist additions go through the same forking dance).

We're happy to put up a PR for this, or equally happy to leave the implementation to a maintainer who knows the codebase better. Filing the issue first to gather feedback and confirm the approach lands cleanly with how you think about gateway extension points.

Related

  • docs/gateway/secrets.md — SecretRef system context.
  • docs/gateway/openai-http-api.md — operator-trust framing for the chat-completions endpoint.
  • docs/tools/skills-config.md — existing skills env field for comparison.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Allow per-call sandbox env injection from operator-trusted callers [1 comments, 2 participants]