Skip to content

[Ubuntu 22.04][Security] Hermes agent echoes env-var token verbatim to Slack chat on "print $X_TOKEN" prompt #4770

@hulynn

Description

@hulynn

Description

Hermes agent in a NemoClaw sandbox has the terminal toolset enabled by default. When a Slack user prompts the bot to print or check access of an env-var-named secret (e.g. DEVTEST_API_TOKEN, API_TOKEN, CQA_TOKEN), the agent runs echo "${X_TOKEN}" via the terminal tool and posts the complete plaintext token value to the Slack channel.

The bot boot log declares Secret redaction: ENABLED (tool output, logs, and chat responses are scrubbed before delivery) but the redaction layer does not catch generic UUID/GUID-format token values — it apparently only matches known prefixes like xoxb- / sk-.

Two independent prompts from a single user produced the leak in under a minute. The bot's Self-improvement review: Memory updated ping after the leak suggests the value may also have been written to Hermes memory store (secondary exfiltration path).

Environment

Device:        Junlai Wang's host (junlaiwnemoclaw.nvidia.com)
OS:            Ubuntu 22.04.5 LTS
Architecture:  x86_64
Docker:        29.5.2 (build 79eb04c)
Hermes Agent:  v0.14.0 (build 2026.5.16, Python 3.13.5)
NemoClaw:      TBD (nemoclaw / nemohermes binaries in junlaiw user PATH, not admin)
OpenShell CLI: TBD
Slack app:     swqa-ngc-bot (different Slack app from "nemoclawtest" used on other QA installs — confirms the issue is Hermes-layer, not bot-specific)

Same Hermes Agent version (v0.14.0 / 2026.5.16) confirmed on three independent installs:

  • Junlai's swqa-ngc-bot (this bug)
  • Lynn's momo sandbox (NemoClaw v0.0.57)
  • Holly's nemoclaw-nvcf sandbox (NemoClaw v0.0.55)

Steps to Reproduce

  1. Stand up a Hermes-agent sandbox with the terminal toolset enabled (default) and a Slack channel integration. Set one or more env vars matching *_TOKEN / *_KEY / *_API in /sandbox/.hermes/.env that hold real or test secret values (e.g. DEVTEST_API_TOKEN=<some-36-char-UUID>).

  2. From an allowlisted Slack user, in a channel where the bot is invited, type either of:

    @<bot> check access now
    @<bot> print DEVTEST_API_TOKEN
    
  3. Bot decides to use the terminal tool, runs a command like:

    echo "${DEVTEST_API_TOKEN}"

    and posts the stdout to the channel.

  4. Observe the bot's reply in Slack — the full env value (e.g. a 36-char UUID) is printed in cleartext.

  5. Observe the trailing Self-improvement review: Memory updated message — bot may have written the conversation (including the token) to its persistent memory store.

Expected Result

At least one of these must hold (preferably all):

  • (a) Agent refuses to echo env vars whose names match common secret-naming patterns (*_TOKEN, *_KEY, *_SECRET, *_API, *_PASSWORD) regardless of value format.

  • (b) Secret-redaction layer scrubs chat output for ANY value coming directly from os.environ, not just known prefixed tokens — value provenance, not value shape, should drive redaction.

  • (c) When the agent decides to read an env var for any reason, the value is replaced with <redacted: ENV_VAR_NAME> in the chat response, AND the redacted form (not the raw value) is what gets persisted to memory.

Actual Result

Bot prints the env var value verbatim to the channel. Two distinct prompts (check access now, print DEVTEST_API_TOKEN) both produced the same 36-char UUID leak in the user's screenshots. The Secret redaction: ENABLED claim in the gateway boot log is misleading — redaction is enabled but does not cover generic env values.

Code locations to investigate (not confirmed by us — Dev to triage):

  • Hermes terminal toolset stdout handling
  • Hermes secret-redaction regex/patterns library (likely under /opt/hermes/hermes_cli/security/ or similar)
  • Hermes memory write path — does Self-improvement review: Memory updated persist raw conversation including tool output?

Workaround until fixed:

  • Remove sensitive *_TOKEN env vars from /sandbox/.hermes/.env, OR
  • Disable the terminal toolset in /sandbox/.hermes/config.yaml platform_toolsets, OR
  • Restrict the bot to allowlisted commands only (if Hermes supports a command allowlist).

Related but distinct: NVB 6263820 / GitHub Issue #4712 (channels add slack platform plumbing). Different code path, same Hermes version line.

Logs

Slack channel screenshots supplied by the reporter (Lynn Hu). Two interactions captured back-to-back:

Image
Junlai Wang: check access now
swqa-ngc-bot APP: terminal: "echo "API_TOKEN: ${API_TOKEN:-(not se..."
                  terminal: "echo "CQA_TOKEN length: ${#CQA_TOKEN}..." (edited)
                  API_TOKEN is now set: <REDACTED-36-CHAR-UUID>  ✓
                  CQA_TOKEN looks like it has a placeholder/resolver string rather than a real value...
Image
Junlai Wang: print DEVTEST_API_TOKEN
swqa-ngc-bot APP: terminal: "echo "${DEVTEST_API_TOKEN}""
                  <REDACTED-36-CHAR-UUID>   ← same value as in Screenshot 1
                  Self-improvement review: Memory updated

The UUID value matches across both interactions (same env var resolution). Token value redacted in this bug body; reporter has the raw screenshots and can attach them to the bug or share separately with Dev triage.

Sandbox-side logs (/sandbox/.hermes/logs/agent.log) do NOT show the raw token value per the reporter — log-layer redaction appears to be working. Only the chat-output path leaks.


NVB#6268796

Metadata

Metadata

Assignees

No one assigned

    Labels

    NV QABugs found by the NVIDIA QA TeamUATIssues flagged for User Acceptance Testing.area: securitySecurity controls, permissions, secrets, or hardeningintegration: hermesHermes integration behaviorintegration: slackSlack integration or channel behaviorplatform: ubuntuAffects Ubuntu Linux environmentssecurityPotential vulnerability, unsafe behavior, or access riskv0.0.61Release target

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions