Skip to content

fix(env): scope ~/.hermes/.env into default profile to prevent cross-profile credential leaks #23

Description

@sergiocoding96

Bug

When a Hermes agent (e.g. research-agent) needs MemOS credentials, it sometimes reads ~/.hermes/.env directly instead of using its already-loaded os.environ. That global file holds the CEO credentials. The agent ends up authenticating with the CEO key against its own cube — which fails (CEO key has no rights on research-cube), wasting turns and producing confusing 401s.

Surfaced during the Phase 6 live-demo smoke test on 2026-04-27. PR #22's SOUL fix (curl → memos_store tool) closes the obvious door but doesn't fix the underlying env-layering ambiguity, which will resurface anywhere else an agent or skill hand-rolls credentials.

Root cause — three overlapping things

  1. Conflicting env files at different scopes. Both ~/.hermes/.env (CEO global) and ~/.hermes/profiles/<agent>/.env (per-agent) exist on disk. At process startup, Hermes loads the profile-scoped one into os.environ correctly. But the global file is not removed or hidden — any process or LLM that reads it gets the CEO scope's key for any non-CEO profile.
  2. LLMs reach for ~/.hermes/.env before os.environ. Behavioral pattern from training data: "find credentials" → cat ~/.env. The agent has no instruction telling it the credentials are already in env vars.
  3. No "this scope's truth" pointer. There's no $HERMES_PROFILE_PATH env var that points at the canonical profile env file.

Symptom (verbatim from session log)

A research-agent task wrote findings to MemOS via curl. Steps 13–16:

[13] terminal: cat ~/.hermes/.env 2>/dev/null | grep -i memos
[14] tool: # === MemOS (CEO raw key from setup-memos-agents.py) ===
           MEMOS_API_KEY=ak_ab95efcdb63247552e8dc1292910802f   ← CEO KEY
[18] tool: {"detail":"Invalid or unknown agent key."}          ← cube ownership rejects

The agent's own process actually had the right env vars set (MEMOS_API_KEY=ak_ebf6642a941f62f0054d597ec99e2a8e, MEMOS_USER_ID=research-agent). The LLM never inspected os.environ; it cat'd the most well-known dotenv path it knew about.

Severity

Medium. Causes silent auth failures and wasted agent turns. Not a security hole — the CEO key only works for the CEO scope; the system fails closed.

Recommended fix — combine A + B

A. SOUL credential-discovery rule (~15 min)

Add a top-level rule in both demo SOULs (and any future agent's SOUL — ideally a shared template):

Credential discovery rule. Your profile-scoped credentials are pre-loaded into your process environment as env vars. Reference them as $VAR_NAME directly. Never read .env files. If you ever feel the need to cat a .env to find an API key, you are about to use the wrong key — stop and use the appropriate tool instead.

B. Rename ~/.hermes/.env so the layering is unambiguous (~30 min)

Move the global file to a profile-scoped location:

~/.hermes/.env  →  ~/.hermes/profiles/default/.env
                   (or ~/.hermes/profiles/ceo/.env)

Update deploy/scripts/setup-memos-agents.py to write CEO credentials into the default-profile file. Audit consumers (grep ~/.hermes/.env across hermes-agent, paperclip, deploy/scripts/) and fix.

After the rename: cat ~/.hermes/.env finds nothing; cat ~/.hermes/profiles/<profile>/.env returns whatever profile is being looked at. Foot-gun gone.

Skipped / deferred

  • Option C ($HERMES_PROFILE_PATH env var) — useful but redundant if A+B land. Revisit if agents need to look up other profile-scoped values besides MemOS creds.
  • Option D (runtime credential-boundary enforcement via LD_PRELOAD / chroot / prompt-engineering hook) — complexity-out-of-proportion-to-benefit for an MVP. Skip.

Acceptance criteria

  1. CEO credentials live at ~/.hermes/profiles/default/.env (or ceo/.env); not at ~/.hermes/.env.
  2. deploy/scripts/setup-memos-agents.py writes to the new location.
  3. All consumers of ~/.hermes/.env updated and re-tested.
  4. deploy/profiles/<all>/SOUL.md (or a shared template) contains the credential-discovery rule.
  5. Smoke test: research-agent and email-marketing agents both successfully write to MemOS without ever reading a .env file. Confirmed via tool-call audit log.

Risk

Medium — touches the setup script and may break external assumptions. Audit consumers carefully before merge.

Effort

~1–2 hours.

References

Activity

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions