Skip to content

Discord, Slack, and Telegram bot tokens bypass OpenShell provider system — injected as plaintext env vars into sandbox #1109

Closed

Description

@zredlined

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:

  1. Read the real bot token from the environment
  2. 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
  3. 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:

  1. openshell provider create --name telegram-bridge --type webhook --credential TELEGRAM_BOT_TOKEN stores the token server-side in the gateway
  2. When the sandbox starts, the runtime fetches credentials via gRPC and replaces each value with openshell:resolve:env:TELEGRAM_BOT_TOKEN in the child process
  3. When the sandbox process makes an HTTP request to api.telegram.org with the placeholder in a header, the L7 proxy (which already has tls: terminate on the Telegram policy) rewrites the header to contain the real token — only in the outbound wire bytes
  4. printenv TELEGRAM_BOT_TOKEN inside the sandbox shows openshell: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

Activity

  1. wscurran commented on Apr 1, 2026

    @wscurran
    Contributor

    ✨ Thanks for the detailed description and reproduction steps! This identifies a problem with Discord, Slack, and Telegram bot tokens being injected as plaintext env vars into sandbox on MacOS. Could you try the fix in PR #1245: fix(cli): clear sandbox registry when gateway is destroyed during onboard?


    Possibly related open PRs:

  2. added and removed on Apr 1, 2026
  3. added a commit that references this issue on Apr 5, 2026
    39b0761
  4. added a commit that references this issue on Apr 6, 2026
    5a7680c
  5. added 2 commits that reference this issue on Apr 14, 2026
    3497340
    cf527e8
  6. added
    area: sandboxOpenShell sandbox lifecycle, runtime, config, or recovery
    and removed on Jun 3, 2026
  7. added theissue type on Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: sandboxOpenShell sandbox lifecycle, runtime, config, or recoveryintegration: discordDiscord integration or channel behaviorintegration: telegramTelegram integration or channel behavior

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions