{"record":{"id":"7a67c3a4a0105cc9","repo":"NousResearch/hermes-agent","slug":"path-is-a-sensitive-credential-file-and-cannot-be","errorCode":null,"errorMessage":"path is a sensitive credential file and cannot be attached","messagePattern":"path is a sensitive credential file and cannot be attached","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/context_references.py","lineNumber":495,"sourceCode":"        try:\n            resolved.relative_to(allowed_root)\n        except ValueError as exc:\n            raise ValueError(\"path is outside the allowed workspace\") from exc\n    return resolved\n\n\ndef _ensure_reference_path_allowed(path: Path) -> None:\n    from hermes_constants import get_hermes_home\n    home = Path(os.path.expanduser(\"~\")).resolve()\n    hermes_home = get_hermes_home().resolve()\n\n    blocked_exact = {home / rel for rel in _SENSITIVE_HOME_FILES}\n    blocked_exact.add(hermes_home / \".env\")\n    blocked_dirs = [home / rel for rel in _SENSITIVE_HOME_DIRS]\n    blocked_dirs.extend(hermes_home / rel for rel in _SENSITIVE_HERMES_DIRS)\n\n    if path in blocked_exact:\n        raise ValueError(\"path is a sensitive credential file and cannot be attached\")\n\n    for blocked_dir in blocked_dirs:\n        try:\n            path.relative_to(blocked_dir)\n        except ValueError:\n            continue\n        raise ValueError(\"path is a sensitive credential or internal Hermes path and cannot be attached\")\n\n    # Anchor to the canonical read deny-list (agent/file_safety.get_read_block_error),\n    # the single source of truth used by the file/terminal read path. The narrow\n    # list above predates that guard and never caught the real credential stores:\n    # provider keys (auth.json), Anthropic OAuth tokens (.anthropic_oauth.json),\n    # MCP OAuth material (mcp-tokens/), webhook HMAC secrets, and project-local\n    # .env files. That gap matters because the gateway feeds UNTRUSTED remote\n    # message text into reference expansion, so `@file:~/.hermes/auth.json` from a\n    # chat peer would otherwise read the operator's keys straight into context.\n    # Routing through the canonical guard closes the gap today and keeps this path\n    # protected automatically whenever that deny-list grows.","sourceCodeStart":477,"sourceCodeEnd":513,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/context_references.py#L477-L513","documentation":"The attached file reference matches a sensitive credential file exactly (e.g. ~/.hermes/.env or a file in _SENSITIVE_HOME_FILES), so reference expansion refuses to inline its contents. This is the first, exact-match tier of _ensure_reference_path_allowed in agent/context_references.py, which protects credential material from being pulled into conversation context.","triggerScenarios":"A message with @file:~/.hermes/.env or @file: pointing at any of the exact sensitive home files (e.g. ~/.ssh/authorized_keys-style entries in _SENSITIVE_HOME_FILES). The resolved Path is compared by equality against blocked_exact.","commonSituations":"Trying to show the agent your configuration for debugging ('read my .env so you can fix the API key'); a remote gateway peer probing for credential files via @file: references.","solutions":["Do not attach credential files; paste only the non-secret key NAMES you need help with.","Create a sanitized copy (secrets redacted) inside the workspace and attach that instead.","Reference documentation or an .env.example file rather than the live .env."],"exampleFix":"# before\n@file:~/.hermes/.env\n# after — sanitized template inside the workspace\n@file:./env.example","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\nCREDENTIAL_NAMES = {'.env', '.env.local'}  # extend to match your policy\n\ndef is_credential_file(p: Path) -> bool:\n    return p.name in CREDENTIAL_NAMES or p.suffix in {'.pem', '.key'}","typeGuard":null,"tryCatchPattern":"try:\n    attach(path)\nexcept ValueError as e:\n    if \"sensitive credential file\" in str(e):\n        # never retry with the same path; offer a redacted copy instead\n        ...","preventionTips":["Never attach live .env / key files; use redacted copies","Reference .env.example templates instead of real secrets","Treat all credential-path blocks as final — do not attempt bypasses"],"tags":["security","credentials","references","path-validation"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}