Skip to content

[Bug]: _secure_dir() resets ~/.hermes to 0700 on every gateway start, breaking nginx serving from subdirectories #6991

@MrBill700

Description

@MrBill700

Bug Description

When nginx (or any web server) serves content from a subdirectory of HERMES_HOME (e.g.
~/.hermes/reports/), the _secure_dir() function in config.py resets ~/.hermes to 0700 on every gateway startup via
ensure_hermes_home(). This removes the execute bit for other users, preventing www-data from traversing into the
directory, resulting in 403 errors.

Steps to Reproduce

Steps to reproduce:

  1. Configure nginx to serve files from a subdirectory of ~/.hermes/ (e.g. alias /home/user/.hermes/reports/;)
  2. Set chmod o+x ~/.hermes so nginx can traverse into it
  3. Restart the hermes-gateway service
  4. Attempt to access the nginx-served content

Expected Behavior

The web server should continue to be able to serve content from subdirectories of HERMES_HOME after
a gateway restart.

Actual Behavior

_secure_dir() resets ~/.hermes to 0700, removing the other-execute bit. nginx returns 403 Forbidden.

Affected Component

CLI (interactive chat)

Messaging Platform (if gateway-related)

Discord

Operating System

ubuntu 24.04.4 LTS

Python Version

3.12.3

Hermes Version

0.8.0

Relevant Logs / Traceback

No traceback — this is a silent permission change, not a crash. The symptom is nginx returning 403
  after gateway restart:

  $ ls -lad ~/.hermes
  drwx------ 21 x x 4096 Apr 9 23:10 /x/x/.hermes

  $ curl -s -o /dev/null -w '%{http_code}' https://x.com/reports/
  403

  After chmod o+x ~/.hermes:
  $ ls -lad ~/.hermes
  drwx-----x 21 x x 4096 Apr 9 23:10 /x/x/.hermes

  $ curl -s -o /dev/null -w '%{http_code}' https://x/reports/
  200

Root Cause Analysis (optional)

_secure_dir() in hermes_cli/config.py unconditionally applies 0o700 to HERMES_HOME and its
subdirectories. It has a carve-out for managed mode (NixOS uses 0o750) but no mechanism for non-managed installs to
preserve the other-execute bit. When any service (nginx, caddy, etc.) needs to traverse HERMES_HOME to reach a served
subdirectory, the blanket 0o700 breaks it on every restart. A possible fix: use 0o701 as the default, or only remove
group/other read+write without touching execute.

Proposed Fix (optional)

In _secure_dir(), change 0o700 to 0o701. This preserves owner-only read/write on HERMES_HOME (configs,
keys, etc. stay protected) while allowing other users to traverse the directory. The execute-only bit on a directory
permits cd-through but not listing contents — web servers can reach explicitly configured subdirectories without
exposing anything else.

Alternatively, a more flexible approach: let users set a custom mode via an env var or config key (e.g.
HERMES_HOME_MODE=0701) so deployments that serve content from subdirectories can opt in without patching source.

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions