Skip to content

Escape reads outside the workspace are browser-only upstream #442

Description

@uzairansaruzi

Part of #395 (item 16). Filed ready-for-human with upstream-change: the authorize step is browser-only at the pin.

Context

Route Handler Contract
POST /api/escape/authorize { session_id, path } routes.py:18065 → workspace.authorize_escape_target returns { token, session_id, workspace_root, surface_path, external_root, external_entry_rel, surface_target, expires_at } (TTL _ESCAPE_AUTH_TTL_SECONDS)
GET /api/escape/list?session_id=&token=&path= :18098 directory listing under the authorized external root
GET /api/escape/file/read?session_id=&token=&path= :18123 file content
GET /api/escape/file/raw?session_id=&token=&path= :14407 raw bytes

Blocker. _handle_escape_authorize returns 403 "browser origin required" unless the request carries an Origin header, then runs _check_csrf, which for an authenticated browser-shaped request requires a CSRF token header that matches a cookie the browser receives. Hermex sends neither and has no CSRF cookie flow (HermesMobile/Networking/APIClient.swift). Faking an Origin to pass as a browser and reverse-engineering the CSRF pairing would be a spoof of upstream's deliberate guard, not a client feature.

What the maintainer needs to decide

  1. Ask upstream for a non-browser path: either honor the session cookie alone for escape/authorize when no Origin is present (the same rule _check_csrf already applies to "non-browser clients"), or a dedicated token endpoint. File the request in nesquena/hermes-webui and link it here.
  2. Or close this as wontfix: symlinked paths outside the workspace stay unreadable from the phone, which is the safe default.

If upstream lands a client path, the expected behavior is

  • In the file tree (feat(workspace): browse the workspace as a lazily loaded file tree #401), a symlink or entry whose target is outside the workspace shows a "Outside workspace" badge. Tapping it authorizes once per session and target, caches the token until expires_at, and browses external_root read-only with the same tree and viewer components. Nothing under an escape token is ever written.
  • Token expiry re-authorizes transparently on the next request.

Acceptance criteria (deferred until the decision)

  • Four Endpoint cases; token cached per server, session, and target with expiry.
  • Read-only enforced in the UI; no 14a or 15 actions under an escape root.
  • Two servers: tokens never cross servers.

Non-goals

Any workaround that sends a fabricated Origin or CSRF header.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestready-for-humanRequires human implementationupstream-changeRoot cause is in hermes-webui/hermes-agent, not this app; link the upstream issue

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions