Skip to content

[Bug]: Background /usage PTY spawns full Claude sessions, auto-accepts trust, and can execute tools/subagents #13086

Closed

Description

@david-lai-jpg

Operating system

macOS

Orca version

Reproduced on v1.4.174 and v1.4.176 (latest stable at the time).

Claude Code: 2.1.224.

Details

Short summary

Orca's background Claude usage/rate-limit machinery starts a real interactive claude PTY without explicit user initiation. The PTY inherits the user's full Claude configuration, hooks, plugins, MCP servers, and authentication. Orca then sends /usage, automatically accepts trust prompts, and repeatedly presses Enter without verifying that Claude is actually at a safe command-palette state.

On my machine this created 82 Claude session UUIDs/artifacts within one 30-minute window. At least one earlier hidden probe escaped the intended local /usage flow and performed real model/tool activity (Read + Agent), including launching a Sonnet subagent. This means an informational background usage probe can consume Claude quota and potentially execute tools or mutate files through user-installed hooks/plugins.

This appears more severe than #12181: that report covers background refresh creating ~/.claude; this report confirms real interactive sessions and model/tool execution.

What happened

Orca's source explicitly starts a full interactive Claude process:

The resulting Claude session hooks contained transcript paths such as:

export CODEX_COMPANION_SESSION_ID='700f543a-8bc8-42f7-8ca7-085bd20def2d'
export CODEX_COMPANION_TRANSCRIPT_PATH='$HOME/.claude/projects/-Users-user-Library-Application-Support-orca-rate-limit-pty-cwd/700f543a-8bc8-42f7-8ca7-085bd20def2d.jsonl'

In the 30 minutes ending at 04:02:32 local time, I counted 82 distinct session IDs whose transcript path resolved to Orca's synthetic working directory:

$HOME/Library/Application Support/orca/rate-limit-pty-cwd

The final burst created new session IDs approximately every 5–7 seconds:

04:01:03  86238cb1-b103-4774-8962-f2a35ad41ed5
04:01:10  ff86644c-9b09-4c62-9e1d-9e8992577594
04:01:16  dc6e0330-f2fd-4927-919e-cbce0b8d2d8c
04:01:21  0d135a56-3fc7-4038-b4d5-825ce965b417
04:01:27  0b695541-446e-40fa-919d-66b2195e6d80
04:01:32  692dbd50-2a68-447b-bbd5-b59b8712c7fa
04:01:37  82c0f436-d7fd-42eb-a718-206ab56765dc
04:01:43  bdbbb404-2d9b-4a3a-b44f-d7f11aa7ed63

Because a single PTY repeatedly presses Enter, the count of Claude session UUIDs is not necessarily identical to the count of OS processes. However, I also captured a real live Claude process and its ancestry:

Orca main
  -> Orca daemon-entry.js
    -> orca-tcc-login
      -> login zsh
        -> claude --dangerously-skip-permissions --verbose
          -> configured MCP/plugin child processes

Concrete PIDs from the capture:

6542  Orca
6917  Orca daemon-entry.js
40547 orca-tcc-login
40579 login zsh
41427 claude --dangerously-skip-permissions --verbose

Immediately before that PTY appeared, daemon.log recorded:

{"ts":"2026-08-07T20:00:29.456Z","event":"client-hello-accepted","clientId":"resolver-health-check"}
{"ts":"2026-08-07T20:00:29.475Z","event":"macos-tcc-pty-spawn","strategy":"wrapped"}
{"ts":"2026-08-07T20:00:29.476Z","pid":40547,"event":"session-created","sessionId":"folder:<redacted>@@d64caabf"}
{"ts":"2026-08-07T20:00:57.468Z","event":"session-exited","sessionId":"folder:<redacted>@@d64caabf","code":0}

The Claude session created at the same time still used Orca's hidden rate-limit-pty-cwd, not the visible project directory.

Confirmed model/tool activity from an earlier hidden probe

A separate hidden session on v1.4.174 had this Claude session-stat entry:

"9cd4d201-42b8-422e-aee1-1822b1351b9d": {
  "tool_counts": {
    "Read": 1,
    "Agent": 1
  },
  "last_tool": "Agent",
  "total_calls": 2,
  "started_at": 1786124400,
  "updated_at": 1786124450
}

Its transcript/project namespace was also Orca's hidden cwd:

$HOME/.claude/projects/-Users-user-Library-Application-Support-orca-rate-limit-pty-cwd/

The Agent tool created a real Sonnet subagent:

{
  "agentType": "codex:codex-rescue",
  "description": "Repair backup script: fix checksum path, add progress output, populate empty folders"
}

OMC recorded the mission starting at 2026-08-07T17:40:16.986Z and completing at 17:40:49.962Z. The parent session ended at 17:41:03.946Z.

I could not recover the deleted parent transcript, so I cannot prove what upstream text caused that unrelated task description to be generated. I can prove that Orca created the parent Claude session in its hidden rate-limit cwd and that the session made model/tool calls.

Behavior while Claude was already at its limit

At the time of the 82-session burst, Claude usage showed 100% used for the five-hour window. The repeated sessions produced limit notifications, but there was no new successful tool activity in ~/.claude/.session-stats.json during that specific 30-minute burst.

That suggests those attempts were rejected at the quota boundary. However, the same behavior after the quota reset could make successful calls again. The earlier 9cd4... session proves the PTY path can reach real inference and tools.

Steps to reproduce

  1. On macOS, install Orca v1.4.176 and authenticate Claude Code.
  2. Have ordinary Claude global hooks/plugins enabled. The problem does not require an Orca automation.
  3. Start Orca and focus/show/restore its main window so usage refresh runs.
  4. Let Claude usage fetching fall back to the PTY path.
  5. Inspect ~/.claude/session-env/*/sessionstart-hook-*.sh.
  6. Observe new session IDs whose transcript paths contain Library-Application-Support-orca-rate-limit-pty-cwd.
  7. Put the Claude account at its five-hour limit and keep Orca focused.
  8. Observe repeated limit notifications and additional hidden session IDs.
  9. Monitor the process tree to see real claude processes spawned beneath Orca/its daemon.

Expected behavior

Background usage tracking must not create an inference-capable Claude session or load the user's hooks, plugins, MCP servers, project instructions, or tool permissions.

A usage probe must never:

  • automatically accept a trust prompt;
  • blindly press Enter without identifying the exact TUI state;
  • allow text to become a normal model prompt;
  • execute tools/subagents;
  • retry in a way that creates many Claude sessions;
  • consume the user's Claude subscription quota.

Suggested fixes

  1. Remove the interactive Claude PTY fallback for automated/background usage refresh. Prefer the OAuth usage endpoint and the existing live statusline usage feed.
  2. If the PTY fallback must remain, make it explicit/manual opt-in and provide a setting to disable it.
  3. Never auto-accept trust prompts in a background usage probe.
  4. Do not send Enter repeatedly. Require an exact, versioned TUI state before sending any input and fail closed otherwise.
  5. Launch probes with hooks/plugins/MCP initialization disabled and without dangerous permission flags.
  6. Add single-flight protection and persistent exponential backoff keyed by provider/account.
  7. Gate the path when Claude is disabled or when no managed/selected Claude account exists.
  8. Add a regression test proving that background usage refresh cannot create a Claude transcript/session or invoke model/tool hooks.

Related issues

No credentials, auth files, or raw environment values are included in this report.

Activity

  1. manuaudio commented on Aug 8, 2026

    @manuaudio
    Contributor

    Confirmed on current main (940f2ff) — plus one gap worth adding

    Verified each anchor in the report against the tree, and found a fourth that explains the 82-session burst specifically.

    Confirmed

    src/main/rate-limits/claude-pty.ts

    • Trust is auto-accepted (~L452-457). The prompt is matched and answered y:
      if (TRUST_PROMPT_RE.test(cleanChunk)) {
        term.write('y\r')
        return
      }
    • Enter is sent blind on a timer (~L383-391) — every 800 ms while unresolved, with no TUI-state check:
      enterInterval = setInterval(() => {
        if (!resolved && !stopDetected) { term.write('\r') }
      }, 800)
    • Startup is a fixed delay, not prompt detection — /usage\r goes out on a 2 s timer regardless of what the CLI is showing.

    The gap not in the report: no single-flight

    fetchViaPty is called straight from fetchClaudeUsageViaCli (claude-fetcher.ts:474) with no in-flight guard anywhere in src/main/rate-limits/ — rg -n 'inflight|inFlight|singleFlight' src/main/rate-limits comes back empty.

    So nothing prevents overlapping probes from each spawning their own claude process. That's the mechanism behind "82 session UUIDs in one 30-minute window" — it isn't only retry cadence, it's concurrent spawns with no mutual exclusion. Suggested fix 6 in the report is, I think, the highest-leverage one for that symptom.

    Offer

    Happy to implement, but the eight suggestions span product decisions I shouldn't make unilaterally — 1 and 2 in particular (remove the fallback vs. make it opt-in) change behavior for anyone relying on the PTY path today.

    The narrow one I'd start with is single-flight, since concurrent duplicate probes seem indefensible regardless of which direction you take the rest. One design question before I write it: fetchViaPty accepts an AbortSignal, so sharing one in-flight promise means one caller's abort would cancel the probe for everyone. Do you want (a) shared promise, aborting only when every waiter has aborted, or (b) a plain "already running" guard where the second caller gets the first one's result and its signal only detaches it?

    Tell me which of the eight you want and I'll open a PR against it.

    (Reported findings verified with Claude Opus 5; no code changes proposed in this comment.)

  2. david-lai-jpg commented on Aug 8, 2026

    @david-lai-jpg
    Author

    Thanks for confirming this against current main and finding the missing single-flight guard.

    For the abort design, please use (a): one internally owned probe per Claude runtime/account target, with per-caller waiters, and abort the underlying PTY only when every waiter has detached or aborted. The first caller's AbortSignal should not own a process shared by later callers.

    My requested priority is:

    1. Fix MaxListenersExceededWarning with singleton PTY dispatcher #6 + Fix update checker 406 error and add menu feedback #8 first: single-flight plus regression coverage proving concurrent refreshes create at most one Claude PTY/session.
    2. Add Shift+Enter to insert newline in terminal #3 and Add Ctrl+Click to open links in terminal #4 as safety requirements: remove automatic trust acceptance and the blind 800 ms Enter loop. If the exact expected usage UI state is not identified, fail closed and terminate the probe.
    3. Fix Ctrl+Backspace not deleting word in terminal #2 for the product behavior: make interactive PTY usage probing explicit opt-in and default it off. That preserves the fallback for users who knowingly need it without silently starting their full Claude environment.

    Single-flight is important containment, but it is not a complete fix for this report: one remaining probe can still inherit hooks/plugins, accept trust, misroute /usage, and reach model/tool execution. I would keep the issue open until the blind-input path is removed or placed behind explicit opt-in.

    One regression case should install a fake Claude executable that presents an unexpected prompt. The test should prove Orca sends neither y nor repeated Enter and exits without starting a second probe when multiple refreshes arrive.

  3. razankv13 commented on Sep 5, 2026

    @razankv13

    I’m seeing the same issue. My Claude usage keeps increasing while Orca ADE is open, even though no Claude task or worker is visibly running. It looks like background usage checks are consuming quota without any user-started Claude work.

  4. added theissue type on Sep 19, 2026
  5. david-lai-jpg commented on Oct 7, 2026

    @david-lai-jpg
    Author

    are you gonna address this issue? this has been going on for a few months now and it is really annoying - burning up my quota just to check my usage that is just plain dumb. i already gave you the solution to fix it. please fix it.

  6. OrcaWin commented on Oct 11, 2026

    @OrcaWin
    Collaborator

    Thanks for the detailed report. This is fixed on main by #26801, which removed the hidden interactive Claude /usage session entirely, so usage refresh no longer starts a Claude process.

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingos:macosIssues affecting macOS

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions