Repository navigation
Fix orchestration agent prompt injection - #7758
Conversation
Co-authored-by: Orca <help@stably.ai>
📝 WalkthroughWalkthroughChangesThis PR adds bracketed-paste framing for terminal agent-prompt injection. Shared helpers in Sequence Diagram(s)Included above within the hidden review stack artifact. Related Issues: Not specified in provided information. Related PRs: Not specified in provided information. Suggested labels: area/runtime, area/orchestration, testing Suggested reviewers: Not specified in provided information. 🐰 A prompt slips in, paste-frame tight, 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 5c3ba0b5-f116-4a80-acf5-8834095a154c
📒 Files selected for processing (10)
config/reliability-gates.jsoncsrc/main/runtime/orca-runtime.test.tssrc/main/runtime/orca-runtime.tssrc/main/runtime/orchestration/coordinator.test.tssrc/main/runtime/orchestration/coordinator.tssrc/main/runtime/rpc/methods/orchestration.test.tssrc/main/runtime/rpc/methods/orchestration.tssrc/shared/agent-prompt-injection.test.tssrc/shared/agent-prompt-injection.tstools/repro-orchestration-long-prompt.mjs
| private async writeTerminalAgentPrompt( | ||
| ptyId: string, | ||
| pastePayload: string, | ||
| options: { | ||
| beforeWrite?: (ptyId: string) => void | Promise<void> | ||
| suffixFailureError?: string | ||
| } = {} | ||
| ): Promise<void> { | ||
| let wrotePasteBytes = false | ||
| let completedPaste = false | ||
| try { | ||
| const chunks = iterateTerminalInputChunks(pastePayload) | ||
| let chunk = chunks.next() | ||
| while (!chunk.done) { | ||
| await options.beforeWrite?.(ptyId) | ||
| const wrote = this.ptyController?.write(ptyId, chunk.value) ?? false | ||
| if (!wrote) { | ||
| throw new Error('terminal_not_writable') | ||
| } | ||
| wrotePasteBytes = true | ||
| chunk = chunks.next() | ||
| if (!chunk.done) { | ||
| await new Promise((resolve) => setTimeout(resolve, 0)) | ||
| } | ||
| } | ||
| completedPaste = true | ||
| } catch (error) { | ||
| if (wrotePasteBytes && !completedPaste) { | ||
| this.ptyController?.write(ptyId, AGENT_PROMPT_BRACKETED_PASTE_END) | ||
| } | ||
| throw error | ||
| } | ||
|
|
||
| await new Promise((resolve) => setTimeout(resolve, AGENT_PROMPT_SUBMIT_DELAY_MS)) | ||
| try { | ||
| await options.beforeWrite?.(ptyId) | ||
| } catch (error) { | ||
| if (options.suffixFailureError) { | ||
| throw new Error(options.suffixFailureError) | ||
| } | ||
| throw error | ||
| } | ||
| const suffixWrote = this.ptyController?.write(ptyId, AGENT_PROMPT_SUBMIT) ?? false | ||
| if (!suffixWrote) { | ||
| throw new Error(options.suffixFailureError ?? 'terminal_not_writable') | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Find other call sites that write to a ptyId that could race
# with an in-flight sendTerminalAgentPrompt/writeTerminalAgentPrompt.
rg -nP --type=ts '\bptyController\??\.write\(' src/main/runtime | grep -v '\.test\.ts'Repository: stablyai/orca
Length of output: 1242
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the relevant areas before reading them.
ast-grep outline src/main/runtime/orca-runtime.ts --view expanded > /tmp/orca-outline.txt || true
# Inspect the surrounding write paths.
sed -n '9160,9275p' src/main/runtime/orca-runtime.ts
printf '\n====\n'
sed -n '12740,12805p' src/main/runtime/orca-runtime.ts
printf '\n====\n'
sed -n '20160,20245p' src/main/runtime/orca-runtime.ts
printf '\n====\n'
# Search for serialization/queue/lock mechanisms keyed by ptyId in runtime.
rg -n "queue|lock|serialize|serialized|in-flight|inflight|mutex|semaphore|ptyId" src/main/runtime/orca-runtime.tsRepository: stablyai/orca
Length of output: 50369
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find the PTY controller implementation and any write serialization.
rg -n "writeChain|class .*Pty|implements PtyController|write\(ptyId: string" src/main/runtime src/main -g '!**/*.test.ts' | head -n 200
printf '\n====\n'
# Inspect the nearby code around any writeChain references.
rg -n -C 4 "writeChain" src/main/runtime/orca-runtime.ts src/main -g '!**/*.test.ts'
printf '\n====\n'
# Find the concrete PTY controller file(s) if present.
fd -a -t f "pty" src/main 2>/dev/null | head -n 100Repository: stablyai/orca
Length of output: 30285
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the PTY write implementations and any serialization around them.
sed -n '300,420p' src/main/providers/local-pty-provider.ts
printf '\n====\n'
sed -n '1,220p' src/main/providers/ssh-pty-provider.ts
printf '\n====\n'
sed -n '1,220p' src/main/daemon/daemon-pty-router.ts
printf '\n====\n'
sed -n '1,220p' src/main/daemon/daemon-pty-adapter.ts
printf '\n====\n'
sed -n '1,220p' src/main/daemon/degraded-daemon-pty-provider.tsRepository: stablyai/orca
Length of output: 38576
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the concrete write implementations for the PTY providers.
rg -n -C 6 "^\s*write\(id: string, data: string\): void|^\s*write\(ptyId: string, data: string\): void|\.write\(.*data" \
src/main/providers/local-pty-provider.ts \
src/main/providers/ssh-pty-provider.ts \
src/main/daemon/daemon-pty-adapter.ts \
src/main/daemon/daemon-pty-router.ts \
src/main/daemon/degraded-daemon-pty-provider.ts \
| head -n 220Repository: stablyai/orca
Length of output: 5092
Serialize agent prompt writes per PTY
writeTerminalAgentPrompt yields between chunks and before the final \r, while ptyController.write(...) is a direct write path with no per-ptyId queue. A concurrent input on the same PTY can splice into the bracketed-paste sequence and break unattended prompt delivery.
Co-authored-by: Orca <help@stably.ai>
Summary
Closes #7226
Validation
Reliability
Made with Orca 🐋