Repository navigation
L7 proxy placeholder-token rewriting doesn't cover WSS payloads — Discord gateway fails with 4004 #913
Description
Agent Diagnostic
Description
Environment
- OpenShell: 0.0.26
- NemoClaw: 2026.4.2 (stack consumer, using blueprint
policies/presets/discord.yaml) - Host: DGX Spark (ARM64), Kubernetes-deployed OpenShell gateway
Summary
OpenShell's L7 proxy rewrites placeholder tokens (openshell:resolve:env:*) at egress for TLS-terminated REST traffic. For gateway.discord.gg the NemoClaw blueprint policy sets tls: skip (per #544, pass-through is required to keep long-lived WSS sessions working). Result: the placeholder flows unchanged inside the WSS IDENTIFY payload; Discord closes with opcode 4004 (auth failed); the bot never connects.
Reproduce
nemoclaw onboard --non-interactivewith a validDISCORD_BOT_TOKEN- Provider
<sandbox>-discord-bridgeis created and attached to the sandbox; sandbox env hasDISCORD_BOT_TOKEN=openshell:resolve:env:DISCORD_BOT_TOKEN - OpenClaw attempts to connect to
wss://gateway.discord.gg - Gateway closes immediately with opcode 4004 (see attached
gateway.log, search for4004)
Confirmation it's a payload-rewrite gap, not a policy/network problem
Writing the real Discord bot token directly into /sandbox/.openclaw/openclaw.json (field channels.discord.accounts.default.token), bypassing the placeholder system for this field, produces a successful IDENTIFY and the bot connects. No policy changes required; the only variable is whether the literal placeholder string or the real token arrives in the WSS IDENTIFY payload.
Proposed directions
- Add WSS MITM + JSON-payload-aware rewriting for known channel protocols (Discord IDENTIFY op 2,
d.tokenfield), sotls: skipcan be removed forgateway.discord.gg. - OR: expose an in-sandbox secret-resolution gRPC endpoint (e.g. reachable via
OPENSHELL_ENDPOINT) that clients can call to resolveopenshell:resolve:env:*explicitly. OpenClaw (and other consumers) could then resolve at config-read time instead of relying on egress rewriting. - OR: when a provider is attached to a sandbox and the target channel is known to use WSS, let OpenShell inject the real credential value into the child env var directly at sandbox start (documenting the security trade-off that the credential is then at-rest in the sandbox env rather than only in the provider store).
Related
- #544 — merged PR that introduced the "auto-terminate TLS unconditionally" behavior;
tls: skipis the escape hatch used by the NemoClaw Discord preset - Credential placeholder model breaks SDKs that validate token format before making network calls #894 — adjacent placeholder-model limitation (SDKs that validate token format pre-network)
Attachments
gateway.log— 344-line log from inside the sandbox (micky pod,/tmp/gateway.log). Shows the 4004 pattern before the manual workaround and the quiet "awaiting gateway readiness" (implicit READY) after.openshell-status.txt—openshell statusopenshell-doctor-check.txt—openshell doctor checkopenshell-doctor-logs.txt—openshell doctor logs --lines 200
Reproduction Steps
-
Deploy a NemoClaw stack (v2026.4.2) with OpenShell 0.0.26 on ARM64 (DGX Spark, k3s).
Blueprint uses policies/presets/discord.yaml which pins gateway.discord.gg totls: skip
(per NVIDIA/OpenShell#544 — required to keep long-lived WSS sessions alive). -
Create a Discord bot credential: nemoclaw credentials set DISCORD_BOT_TOKEN
-
Onboard the sandbox (this creates provider
<sandbox>-discord-bridgeand attaches it):
nemoclaw onboard --non-interactive -
Confirm the sandbox env contains the placeholder, not the real token:
kubectl exec -n nemoclaw deploy/micky -- printenv DISCORD_BOT_TOKEN=> openshell:resolve:env:DISCORD_BOT_TOKEN
-
Start OpenClaw inside the sandbox so it connects to Discord:
kubectl exec -n nemoclaw deploy/micky -- openclaw start -
Observe gateway.log — OpenClaw opens wss://gateway.discord.gg, sends IDENTIFY op 2
withd.tokenset to the literal string "openshell:resolve:env:DISCORD_BOT_TOKEN",
Discord closes the socket with opcode 4004 (Authentication Failed).
Expected: IDENTIFY carries the resolved bot token; gateway sends READY; bot comes online.
Actual: IDENTIFY carries the literal placeholder string; gateway closes with 4004.
Workaround (confirms payload-rewrite gap, not a policy/network problem):
Edit /sandbox/.openclaw/openclaw.json inside the pod, set
channels.discord.accounts.default.token to the real token value from
~/.nemoclaw/credentials.json. OpenClaw hot-reloads, IDENTIFY now carries the real
token, Discord sends READY, bot connects. No policy changes required.
Environment
OpenShell: 0.0.26
NemoClaw: 2026.4.2 (blueprint: policies/presets/discord.yaml)
OpenClaw: 2026.4.9
Host: NVIDIA DGX Spark (GB10 Grace Blackwell, ARM64 / aarch64)
OS: Ubuntu 24.04 LTS (kernel 6.11, CUDA 13.0)
Runtime: k3s (single-node), containerd
Sandbox pod: micky (namespace: nemoclaw)
Storage: local-path PVC workspace-micky (2Gi) mounted at /sandbox
Client: Discord gateway via ws npm library (raw tls.connect, ignores HTTPS_PROXY)
Policy: gateway.discord.gg → tls: skip (L4 CONNECT pass-through)
Network: OpenShell L7 proxy at 10.200.0.1:3128 (CONNECT + TLS-MITM for REST egress)
Logs
Agent-First Checklist
- I pointed my agent at the repo and had it investigate this issue
- I loaded relevant skills (e.g.,
debug-openshell-cluster,debug-inference,openshell-cli) - My agent could not resolve this — the diagnostic above explains why
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
github-actions commentedon Aug 30, 2026
This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.