Loopback HTTP API publishes the action token and does not pin Host
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 94
- Forks
- 16
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 5
Description
Summary
The Token Meter server binds 127.0.0.1:8722 with no authentication. Mutation POSTs are gated by X-Token-Meter-Action, but that token is generated once at process start and then returned in ordinary GET JSON (/state, /session, /updates/status, /menubar).
GET handlers do not check Host or Origin. POST origin checks are skipped when the Origin header is absent:
origin = self.headers.get("Origin") or ""
if origin and (urlparse(origin).hostname or "") not in ("localhost", "127.0.0.1", "::1"):
...
Impact
Anyone who can speak to loopback can read session metadata, costs, project names, and the live action token, then call:
POST /session/delete(move discovered.jsonllogs to Trash)POST /agent-access/toggle(add/remove thetokenmeterMCP entry in Codex/Claude)POST /capability/toggleand/capability/disable-unused(rewrite Claude/Codex plugin settings)POST /updates/install(fetch + reinstall)
That includes every local UID on a shared machine (curl 127.0.0.1:8722/state). DNS rebinding is also in play because there is no Host allowlist: GET is enough to exfiltrate the token and dashboard JSON. Classic HTML-form CSRF is mostly blocked by the JSON content-type requirement; local processes and rebinding pages are not.
Where
token_meter/web/server.py(bind address)token_meter/app.py(_ACTION_TOKEN,software_update_status,do_GET/do_POST)menubar_software_update()also copies the token into/menubar
Suggested fix
- Reject any request whose
Hostis not127.0.0.1,localhost, or::1(with optional port). - Do not put the action token on unauthenticated GET JSON. Prefer a
SameSite=Strictcookie, or a one-time bootstrap that is not readable cross-origin. - Require a loopback
Originon browser POSTs; do not treat a missingOriginas trusted. - Add
Content-Security-Policy: frame-ancestors 'none'andX-Frame-Options: DENYso the dashboard cannot be clickjacked.
Happy to send a patch against a fork if useful.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading token_meter/web/server.py and the _ACTION_TOKEN, software_update_status, do_GET, do_POST, and menubar_software_update paths in token_meter/app.py. Trace how Host, Origin, GET JSON, and mutation requests are handled. Done means loopback host and browser-origin checks are enforced, GET responses no longer expose the action token, and the stated security headers protect the dashboard.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100