Skip to content

fix(dashboard): block .env files from managed-files API - #57507

Closed
liuhao1024 wants to merge 2 commits into
NousResearch:mainfrom
liuhao1024:liuhao/cron-bugfix-57505-env-file-leak
Closed

liuhao1024 wants to merge 2 commits into
NousResearch:mainfrom
liuhao1024:liuhao/cron-bugfix-57505-env-file-leak

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

What does this PR do?

Blocks the dashboard managed-files API from listing, reading, or downloading sensitive credential files (.env, .env.local, etc.). Previously, when the dashboard was run with a bind-mounted Hermes home directory (e.g. docker run -v ~/.hermes:/opt/data), the Files tab could browse and download .env files containing API keys and tokens.

Related Issue

Fixes #57505

Type of Change

  • 🔒 Security fix
  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • hermes_cli/web_server.py: Added _SENSITIVE_FILENAMES frozenset containing .env and common variants. Filtered these filenames from list_managed_files() directory listings and added 403 guards to read_managed_file() and download_managed_file().
  • tests/hermes_cli/test_web_server_files.py: Added 3 regression tests verifying .env files are hidden from listings, blocked from read, and blocked from download.

How to Test

  1. Run python -m pytest tests/hermes_cli/test_web_server_files.py -q — all 19 tests should pass (including the 3 new regression tests).
  2. Manual: start the dashboard with hermes dashboard, navigate to the Files tab, verify .env files do not appear in directory listings.
  3. Manual: attempt to directly access /api/files/read?path=.../.env — should return 403.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/hermes_cli/test_web_server_files.py -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 26.4.1

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Screenshots / Logs

N/A — security fix with regression tests.

The dashboard Files tab could list, read, and download .env files
containing API keys when running with a bind-mounted Hermes home
directory (e.g. docker run -v ~/.hermes:/opt/data).

Add _SENSITIVE_FILENAMES frozenset and filter these from
list_managed_files(), read_managed_file(), and download_managed_file().
Return 403 for direct read/download attempts on sensitive files.

Fixes NousResearch#57505
@alt-glitch alt-glitch added type/security Security vulnerability or hardening P1 High — major feature broken, no workaround comp/dashboard Web dashboard / control panel UI (dashboard/, landing) area/auth Authentication, OAuth, credential pools sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Jul 3, 2026
@egilewski

Copy link
Copy Markdown
Contributor

suggesting changes

Security evidence:

  • trust boundary: the dashboard managed-files API exposes files from the configured Hermes home or forced files root to an authenticated dashboard client, so credential-like environment files under that root must not be listed, read, or downloaded.
  • source/sink/invariant: the source is a filesystem entry resolved by _resolve_managed_path() or target.iterdir() in hermes_cli/web_server.py; the sinks are /api/files, /api/files/read, and /api/files/download; the invariant is that environment credential files are withheld regardless of whether the operator named a common suffix variant.
  • current-main reproduction: the run-root probe imported hermes_cli/web_server.py from current main and showed .env, .env.local, and .env.prod are all listed, readable, and downloadable with HTTP 200.
  • PR-head or patch-replay validation: the same probe imported hermes_cli/web_server.py from PR head 1b58988 and showed .env and .env.local now return HTTP 403 and are hidden from listing, but .env.prod is still listed and both read/download return HTTP 200.
  • remaining blocker: because the guard is an exact filename set containing .env.production but not common shorthand variants such as .env.prod, any unlisted .env.<suffix> credential file remains exposed through the same managed-files API the PR is trying to harden.
  • validation: the submitted focused test file passes as 19 passed, and the probe confirmed a normal config.txt remains listed/readable/downloadable on PR head while the credential-style .env.prod negative case is still exposed.

Please make the sensitive-file guard cover .env plus credential-style .env.<suffix> names by policy rather than only the currently enumerated examples, and add a regression for a variant such as .env.prod so future suffix drift does not reopen this leak.

Signed: GPT-5.5-xhigh in Codex

Replace the exact-filename frozenset with _is_sensitive_filename()
that matches .env plus any .env.<suffix> variant.  This covers
shorthand suffixes like .env.prod that the previous enumeration
missed.

Add test_sensitive_env_suffix_variants_blocked regression test
covering .env.prod, .env.dev, .env.staging.local, and .env.ci.

Addresses review feedback from egilewski on PR NousResearch#57507.
@liuhao1024

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough security review! You're right — the exact-filename set missed shorthand variants like .env.prod.

Pushed a fix that replaces _SENSITIVE_FILENAMES frozenset with a pattern-based _is_sensitive_filename() helper:

def _is_sensitive_filename(name: str) -> bool:
    """Return True for ``.env`` and any ``.env.<suffix>`` variant."""
    return name == ".env" or name.startswith(".env.")

This covers all .env.<suffix> variants by policy rather than enumeration. Added test_sensitive_env_suffix_variants_blocked regression test covering .env.prod, .env.dev, .env.staging.local, and .env.ci.

All 20 tests pass.

@egilewski

Copy link
Copy Markdown
Contributor

suggesting changes

Security evidence:

  • trust boundary: the dashboard managed-files API exposes files from the configured Hermes home or forced files root to an authenticated dashboard client, so credential-style environment files under that root must not be listed, read, or downloaded.
  • source/sink/invariant: the source is a resolved filesystem entry in hermes_cli/web_server.py; the sinks are /api/files, /api/files/read, and /api/files/download; the invariant is that .env credential variants remain withheld regardless of common suffix or case spelling.
  • current-main reproduction: a run-root probe imported current main at 551e5af and showed .env, .env.local, .env.prod, .env.staging.local, .ENV, and .Env.local were all listed, readable, and downloadable with HTTP 200.
  • PR-head validation: the same probe imported PR head 2099781 and showed lowercase .env, .env.local, .env.prod, and .env.staging.local are now hidden and return HTTP 403, but .ENV and .Env.local are still listed and return HTTP 200 for both read and download.
  • remaining blocker: _is_sensitive_filename() currently checks name == ".env" or name.startswith(".env."), so case variants still bypass the same managed-files API guard this PR is adding; this is especially relevant for cross-platform operator environments where users may create or mount case-variant environment files.
  • reviewer validation: CodeRabbit reported the case-variant bypass, and I reproduced it with the synthetic API probe above; tests/hermes_cli/test_web_server_files.py -q still passes as 20 passed.

Please make the sensitive filename predicate case-insensitive for .env and .env.<suffix> variants, and add a regression for at least one case variant such as .ENV or .Env.local so the dashboard file API cannot expose those credential files.

Signed: GPT-5.5-xhigh in Codex

teknium1 pushed a commit that referenced this pull request Jul 3, 2026
Replace the exact-filename frozenset with _is_sensitive_filename()
that matches .env plus any .env.<suffix> variant.  This covers
shorthand suffixes like .env.prod that the previous enumeration
missed.

Add test_sensitive_env_suffix_variants_blocked regression test
covering .env.prod, .env.dev, .env.staging.local, and .env.ci.

Addresses review feedback from egilewski on PR #57507.
teknium1 added a commit that referenced this pull request Jul 3, 2026
Follow-up to #57507: .ENV / .Env.local on case-insensitive filesystem
mounts slipped past the guard. Lowercase the name before matching and
add a regression test. Addresses egilewski's open review note.
@teknium1

teknium1 commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Merged via PR #57660 — both of your commits (the initial guard and the pattern-match follow-up) were cherry-picked onto current main with your authorship preserved (rebase-merge). We added one small follow-up on top making the guard case-insensitive (.ENV / .Env.local on case-insensitive filesystem mounts) per the open review note, with a regression test. This closes #57505. Thanks for the responsive iteration on review feedback!

@teknium1 teknium1 closed this Jul 3, 2026
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
Replace the exact-filename frozenset with _is_sensitive_filename()
that matches .env plus any .env.<suffix> variant.  This covers
shorthand suffixes like .env.prod that the previous enumeration
missed.

Add test_sensitive_env_suffix_variants_blocked regression test
covering .env.prod, .env.dev, .env.staging.local, and .env.ci.

Addresses review feedback from egilewski on PR NousResearch#57507.
habarmc1223-sudo pushed a commit to habarmc1223-sudo/hermes-agent-fluxmem that referenced this pull request Jul 8, 2026
Follow-up to NousResearch#57507: .ENV / .Env.local on case-insensitive filesystem
mounts slipped past the guard. Lowercase the name before matching and
add a regression test. Addresses egilewski's open review note.
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
Replace the exact-filename frozenset with _is_sensitive_filename()
that matches .env plus any .env.<suffix> variant.  This covers
shorthand suffixes like .env.prod that the previous enumeration
missed.

Add test_sensitive_env_suffix_variants_blocked regression test
covering .env.prod, .env.dev, .env.staging.local, and .env.ci.

Addresses review feedback from egilewski on PR NousResearch#57507.
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
Follow-up to NousResearch#57507: .ENV / .Env.local on case-insensitive filesystem
mounts slipped past the guard. Lowercase the name before matching and
add a regression test. Addresses egilewski's open review note.
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
Replace the exact-filename frozenset with _is_sensitive_filename()
that matches .env plus any .env.<suffix> variant.  This covers
shorthand suffixes like .env.prod that the previous enumeration
missed.

Add test_sensitive_env_suffix_variants_blocked regression test
covering .env.prod, .env.dev, .env.staging.local, and .env.ci.

Addresses review feedback from egilewski on PR NousResearch#57507.
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
Follow-up to NousResearch#57507: .ENV / .Env.local on case-insensitive filesystem
mounts slipped past the guard. Lowercase the name before matching and
add a regression test. Addresses egilewski's open review note.
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
Replace the exact-filename frozenset with _is_sensitive_filename()
that matches .env plus any .env.<suffix> variant.  This covers
shorthand suffixes like .env.prod that the previous enumeration
missed.

Add test_sensitive_env_suffix_variants_blocked regression test
covering .env.prod, .env.dev, .env.staging.local, and .env.ci.

Addresses review feedback from egilewski on PR NousResearch#57507.
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
Follow-up to NousResearch#57507: .ENV / .Env.local on case-insensitive filesystem
mounts slipped past the guard. Lowercase the name before matching and
add a regression test. Addresses egilewski's open review note.
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
Replace the exact-filename frozenset with _is_sensitive_filename()
that matches .env plus any .env.<suffix> variant.  This covers
shorthand suffixes like .env.prod that the previous enumeration
missed.

Add test_sensitive_env_suffix_variants_blocked regression test
covering .env.prod, .env.dev, .env.staging.local, and .env.ci.

Addresses review feedback from egilewski on PR NousResearch#57507.
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
Follow-up to NousResearch#57507: .ENV / .Env.local on case-insensitive filesystem
mounts slipped past the guard. Lowercase the name before matching and
add a regression test. Addresses egilewski's open review note.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/dashboard Web dashboard / control panel UI (dashboard/, landing) P1 High — major feature broken, no workaround sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Security: Dashboard "Files" feature exposes .env containing API keys

4 participants