mirror of
https://github.com/stablyai/orca.git
synced 2026-10-17 08:03:14 +00:00
fix(agent-hooks): parse endpoint file and keep hook secrets off argv
The managed shell/cmd hook scripts sourced the endpoint file (`. "$file"` / `call "%file%"`), so any shell/batch written into that path executed with the agent's privileges. They also passed the hook token and the raw payload as curl command-line arguments (readable by other same-UID processes via `ps`/`/proc/<pid>/cmdline`) and did not disable proxying for the loopback POST. Add a shared builder (`agent-hooks/managed-hook-script.ts`) used by every shell/cmd hook: - Parse only the four known ORCA_AGENT_HOOK_* keys from the endpoint file; never execute it. Values are assigned as literals, so a command substitution in the file is stored, not run. - Stream the token into curl as a header from stdin (`-H @-`) and read the payload from a private temp file (`--data-urlencode payload@<file>`), so neither appears on the command line. - Add `--noproxy 127.0.0.1` so a configured http_proxy/ALL_PROXY cannot route the token and prompt off-box. - Validate the port as digits-only; keep the Claude hook silent on stdout. The JS, Python, and PowerShell hooks already parsed the file and sent the token as an in-process header, so they are unchanged. On Windows cmd the token stays on argv (no mktemp; stdin is taken by the payload) — a documented, same-user-only exposure matching the already-ACL'd endpoint file. STA-1284 Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
import { buildWindowsAgentHookPostCommand } from '../agent-hooks/installer-utils'
|
||||
import {
|
||||
buildPosixSecureCurlPostLines,
|
||||
buildWindowsEndpointSubroutineLines
|
||||
} from '../agent-hooks/managed-hook-script'
|
||||
|
||||
export type CommandCodeManagedScriptTarget = 'local' | 'posix'
|
||||
|
||||
@@ -9,7 +13,11 @@ export function buildCommandCodeManagedScript(
|
||||
return [
|
||||
'@echo off',
|
||||
'setlocal',
|
||||
'if "%ORCA_AGENT_HOOK_PORT%"=="" if defined ORCA_AGENT_HOOK_ENDPOINT if exist "%ORCA_AGENT_HOOK_ENDPOINT%" call "%ORCA_AGENT_HOOK_ENDPOINT%" 2>nul',
|
||||
// Why: the endpoint file(s) are parsed, never executed, so untrusted
|
||||
// content in that path cannot run. Command Code sanitizes the hook env, so
|
||||
// when the primary endpoint is missing we still search %APPDATA% for the
|
||||
// endpoint.cmd whose port matches the recovered loopback port.
|
||||
'if "%ORCA_AGENT_HOOK_PORT%"=="" call :__orcaLoadEndpoint',
|
||||
'if "%ORCA_AGENT_HOOK_TOKEN%"=="" if not "%ORCA_AGENT_HOOK_PORT%"=="" call :sourceEndpointByPort',
|
||||
'if "%ORCA_AGENT_HOOK_PORT%"=="" exit /b 0',
|
||||
'if "%ORCA_AGENT_HOOK_TOKEN%"=="" exit /b 0',
|
||||
@@ -23,8 +31,9 @@ export function buildCommandCodeManagedScript(
|
||||
'exit /b 0',
|
||||
':maybeSourceEndpoint',
|
||||
'if not "%ORCA_AGENT_HOOK_TOKEN%"=="" exit /b 0',
|
||||
'for /f "tokens=2 delims==" %%P in (\'findstr /b /c:"set ORCA_AGENT_HOOK_PORT=" "%~1" 2^>nul\') do if "%%P"=="%ORCA_AGENT_HOOK_PORT%" call "%~1" 2>nul',
|
||||
'for /f "tokens=2 delims==" %%P in (\'findstr /b /c:"set ORCA_AGENT_HOOK_PORT=" "%~1" 2^>nul\') do if "%%P"=="%ORCA_AGENT_HOOK_PORT%" call :__orcaParseEndpointFile "%~1"',
|
||||
'exit /b 0',
|
||||
...buildWindowsEndpointSubroutineLines(),
|
||||
''
|
||||
].join('\r\n')
|
||||
}
|
||||
@@ -116,25 +125,7 @@ export function buildCommandCodeManagedScript(
|
||||
'if [ -z "$ORCA_AGENT_HOOK_PORT" ] || [ -z "$ORCA_AGENT_HOOK_TOKEN" ] || [ -z "$ORCA_PANE_KEY" ]; then',
|
||||
' exit 0',
|
||||
'fi',
|
||||
'payload=$(cat)',
|
||||
'if [ -z "$payload" ]; then',
|
||||
' exit 0',
|
||||
'fi',
|
||||
// Timeout caps best-effort hook posts if the local listener stalls.
|
||||
// Why: pipe payload to curl's stdin (`payload@-`) instead of an inline
|
||||
// `payload=$VALUE` arg, so tens-of-KB tool output stays off the curl
|
||||
// command line (EDR command-line false positives). Wire body is identical.
|
||||
'printf \'%s\' "$payload" | curl -sS -X POST "http://127.0.0.1:${ORCA_AGENT_HOOK_PORT}/hook/command-code" \\',
|
||||
' --connect-timeout 0.5 --max-time 1.5 \\',
|
||||
' -H "Content-Type: application/x-www-form-urlencoded" \\',
|
||||
' -H "X-Orca-Agent-Hook-Token: ${ORCA_AGENT_HOOK_TOKEN}" \\',
|
||||
' --data-urlencode "paneKey=${ORCA_PANE_KEY}" \\',
|
||||
' --data-urlencode "tabId=${ORCA_TAB_ID}" \\',
|
||||
' --data-urlencode "launchToken=${ORCA_AGENT_LAUNCH_TOKEN}" \\',
|
||||
' --data-urlencode "worktreeId=${ORCA_WORKTREE_ID}" \\',
|
||||
' --data-urlencode "env=${ORCA_AGENT_HOOK_ENV}" \\',
|
||||
' --data-urlencode "version=${ORCA_AGENT_HOOK_VERSION}" \\',
|
||||
' --data-urlencode "payload@-" >/dev/null 2>&1 || true',
|
||||
...buildPosixSecureCurlPostLines({ source: 'command-code' }),
|
||||
'exit 0',
|
||||
''
|
||||
].join('\n')
|
||||
|
||||
Reference in New Issue
Block a user