[Bug]: Background /usage PTY spawns full Claude sessions, auto-accepts trust, and can execute tools/subagents
- Dominant language
- TypeScript
- Stars
- 71.3k
- Forks
- 4.7k
- Avg merge
- 17h 8m
- Merged PRs (30d)
- 475
Description
### 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:
- [`claude-pty.ts` describes an interactive `/usage` fallback](https://github.com/stablyai/orca/blob/8c3e9535c75b379ca9ac68b5d35ddfca196ea3df/src/main/rate-limits/claude-pty.ts#L20-L22)
- [prompt detection is intentionally skipped in favor of a fixed 2-second delay](https://github.com/stablyai/orca/blob/8c3e9535c75b379ca9ac68b5d35ddfca196ea3df/src/main/rate-limits/claude-pty.ts#L166-L177)
- [`pty.spawn()` launches `claude` with no arguments in `rate-limit-pty-cwd`](https://github.com/stablyai/orca/blob/8c3e9535c75b379ca9ac68b5d35ddfca196ea3df/src/main/rate-limits/claude-pty.ts#L238-L296)
- [the PTY presses Enter every 800 ms](https://github.com/stablyai/orca/blob/8c3e9535c75b379ca9ac68b5d35ddfca196ea3df/src/main/rate-limits/claude-pty.ts#L381-L391)
- [it sends `/usage`, starts the Enter loop, and automatically answers trust prompts with `y`](https://github.com/stablyai/orca/blob/8c3e9535c75b379ca9ac68b5d35ddfca196ea3df/src/main/rate-limits/claude-pty.ts#L431-L464)
The resulting Claude session hooks contained transcript paths such as:
```sh
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:
```text
$HOME/Library/Application Support/orca/rate-limit-pty-cwd
```
The final burst created new session IDs approximately every 5–7 seconds:
```text
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:
```text
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:
```text
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:
```json
{"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:@@d64caabf"}
{"ts":"2026-08-07T20:00:57.468Z","event":"session-exited","sessionId":"folder:@@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:
```json
"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:
```text
$HOME/.claude/projects/-Users-user-Library-Application-Support-orca-rate-limit-pty-cwd/
```
The `Agent` tool created a real Sonnet subagent:
```json
{
"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
- #12181 — background usage refresh creates `~/.claude` even when Claude is disabled.
- #9616 — usage 429 handling and focus/restore retry behavior.
No credentials, auth files, or raw environment values are included in this report.
Contributor guide
Assessment
This issue has not been assessed yet.