-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Description
Summary
During sandbox creation, Discord and Slack bot tokens are passed directly into the sandbox as plaintext environment variables (onboard.js:1810-1817). The Telegram bot token follows the same pattern via the bridge's SSH command (telegram-bridge.js:108, covered in #1108). These tokens are readable by any process inside the sandbox via printenv or /proc/self/environ.
const sandboxEnv = { ...process.env };
delete sandboxEnv.NVIDIA_API_KEY; // correctly removed for inference
const discordToken = getCredential("DISCORD_BOT_TOKEN") || process.env.DISCORD_BOT_TOKEN;
if (discordToken) {
sandboxEnv.DISCORD_BOT_TOKEN = discordToken; // raw secret injected
}
const slackToken = getCredential("SLACK_BOT_TOKEN") || process.env.SLACK_BOT_TOKEN;
if (slackToken) {
sandboxEnv.SLACK_BOT_TOKEN = slackToken; // raw secret injected
}Why this matters
A compromised or misaligned agent inside the sandbox can:
- Read the real bot token from the environment
- Use the allowed egress path to the messaging service (the Telegram, Discord, and Slack policies already exist in
openclaw-sandbox.yaml) to exfiltrate data or impersonate the bot - Use the token to interact with messaging APIs beyond what the agent is supposed to do
The whole point of the OpenShell provider system is that the sandbox process should never see the real credential value.
How OpenShell's provider system handles this
OpenShell's SecretResolver replaces real credential values with opaque placeholders in the sandbox process environment. The flow:
openshell provider create --name telegram-bridge --type webhook --credential TELEGRAM_BOT_TOKENstores the token server-side in the gateway- When the sandbox starts, the runtime fetches credentials via gRPC and replaces each value with
openshell:resolve:env:TELEGRAM_BOT_TOKENin the child process - When the sandbox process makes an HTTP request to
api.telegram.orgwith the placeholder in a header, the L7 proxy (which already hastls: terminateon the Telegram policy) rewrites the header to contain the real token — only in the outbound wire bytes printenv TELEGRAM_BOT_TOKENinside the sandbox showsopenshell:resolve:env:TELEGRAM_BOT_TOKEN— never the real value
This mechanism is completely generic. The provider type field is free-form and the credential injection pipeline works for any key-value pair. No OpenShell code changes are needed — the same system that handles NVIDIA_API_KEY and ANTHROPIC_API_KEY works for TELEGRAM_BOT_TOKEN, DISCORD_BOT_TOKEN, and SLACK_BOT_TOKEN today.
Suggested fix
Replace raw env var injection with provider registration for all messaging credentials:
# During onboard or service setup — credentials stored server-side
openshell provider create --name telegram-creds --type webhook --credential TELEGRAM_BOT_TOKEN
openshell provider create --name discord-creds --type webhook --credential DISCORD_BOT_TOKEN
openshell provider create --name slack-creds --type webhook --credential SLACK_BOT_TOKEN
# Attach providers to the sandbox at creation
openshell sandbox create \
--provider nvidia-prod \
--provider telegram-creds \
--provider discord-creds \
--provider slack-creds \
...Then remove these lines from onboard.js:
// DELETE — no longer needed; provider system handles injection
sandboxEnv.DISCORD_BOT_TOKEN = discordToken;
sandboxEnv.SLACK_BOT_TOKEN = slackToken;The existing L7 network policies in openclaw-sandbox.yaml for Telegram, Discord, and Slack already use protocol: rest with tls: terminate, which is exactly what's needed for the proxy to perform header rewriting.
Relationship to existing issues
- chore: unify credential passing pattern across all integrations #616 identified the inconsistency across credential patterns and proposed standardizing on env vars. This issue goes further: stop using raw env vars for secrets entirely, and use the OpenShell provider system's placeholder-based credential injection instead.
- Telegram bridge bypasses OpenShell credential isolation — raw NVIDIA_API_KEY injected into sandbox via SSH #1108 covers the specific case of the Telegram bridge injecting
NVIDIA_API_KEYvia SSH. - CRITICAL: NVIDIA API Key Exposed in Process Arguments and Terminal Output #579 covers
NVIDIA_API_KEYprocess-argument exposure, which has been partially fixed. This issue covers the remaining messaging tokens that still bypass the provider system.