mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-06 08:10:48 +00:00
fix: Prevent shell/Python injection in Codespaces, Render, and FluidStack (#252)
GitHub Codespaces scripts embedded API keys directly into heredocs sent over SSH, allowing single-quote breakout for command injection. Fixed by adding upload_file/run_server/inject_env_vars helpers to Codespaces lib and using safe temp-file-upload pattern (matching Railway/Render). Render claude.sh and openclaw.sh built JSON config via unescaped heredocs. Fixed by using shared setup_claude_code_config/setup_openclaw_config helpers which properly json_escape values. FluidStack had triple-quote injection in SSH key registration (pub_key embedded in Python triple-quotes) and missing single-quote validation in create_server env var checks. Fixed by reading values via stdin/argv instead of string interpolation, and added single-quote to validation. Agent: security-auditor Co-authored-by: A <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
281ea2a74f
commit
f39ffd6e24
8 changed files with 108 additions and 159 deletions
|
|
@ -31,12 +31,15 @@ fi
|
|||
|
||||
log_info "Codespace created: $CODESPACE"
|
||||
|
||||
# Set CODESPACE_NAME for upload_file/run_server/inject_env_vars helpers
|
||||
CODESPACE_NAME="$CODESPACE"
|
||||
|
||||
# 3. Wait for codespace to be ready
|
||||
wait_for_codespace "$CODESPACE"
|
||||
|
||||
# 4. Install Aider
|
||||
log_warn "Installing Aider..."
|
||||
run_in_codespace "$CODESPACE" "pip install aider-chat 2>/dev/null || pip3 install aider-chat"
|
||||
run_server "pip install aider-chat 2>/dev/null || pip3 install aider-chat"
|
||||
log_info "Aider installed"
|
||||
|
||||
# 5. Get OpenRouter API key
|
||||
|
|
@ -50,16 +53,9 @@ fi
|
|||
# 6. Get model preference
|
||||
MODEL_ID=$(get_model_id_interactive "openrouter/auto" "Aider") || exit 1
|
||||
|
||||
# 7. Inject environment variables into ~/.bashrc
|
||||
log_warn "Setting up environment variables..."
|
||||
|
||||
ENV_VARS="
|
||||
export OPENROUTER_API_KEY='${OPENROUTER_API_KEY}'
|
||||
"
|
||||
|
||||
run_in_codespace "$CODESPACE" "cat >> ~/.bashrc << 'ENVEOF'
|
||||
$ENV_VARS
|
||||
ENVEOF"
|
||||
# 7. Inject environment variables via safe temp file upload
|
||||
inject_env_vars \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}"
|
||||
|
||||
echo ""
|
||||
log_info "GitHub Codespace setup completed successfully!"
|
||||
|
|
@ -73,4 +69,4 @@ echo ""
|
|||
sleep 1
|
||||
|
||||
# Launch Aider with model
|
||||
run_in_codespace "$CODESPACE" "source ~/.bashrc && aider --model openrouter/${MODEL_ID}"
|
||||
run_server "source ~/.bashrc && aider --model openrouter/${MODEL_ID}"
|
||||
|
|
|
|||
|
|
@ -31,15 +31,18 @@ fi
|
|||
|
||||
log_info "Codespace created: $CODESPACE"
|
||||
|
||||
# Set CODESPACE_NAME for upload_file/run_server/inject_env_vars helpers
|
||||
CODESPACE_NAME="$CODESPACE"
|
||||
|
||||
# 3. Wait for codespace to be ready
|
||||
wait_for_codespace "$CODESPACE"
|
||||
|
||||
# 4. Install Claude Code
|
||||
log_warn "Installing Claude Code..."
|
||||
run_in_codespace "$CODESPACE" "curl -fsSL https://claude.ai/install.sh | bash"
|
||||
run_server "curl -fsSL https://claude.ai/install.sh | bash"
|
||||
|
||||
# Verify installation
|
||||
if ! run_in_codespace "$CODESPACE" "command -v claude" &>/dev/null; then
|
||||
if ! run_server "command -v claude" &>/dev/null; then
|
||||
log_error "Claude Code installation failed"
|
||||
delete_codespace "$CODESPACE"
|
||||
exit 1
|
||||
|
|
@ -54,59 +57,18 @@ else
|
|||
OPENROUTER_API_KEY=$(get_openrouter_api_key_oauth 5180)
|
||||
fi
|
||||
|
||||
# 6. Inject environment variables into ~/.bashrc
|
||||
log_warn "Setting up environment variables..."
|
||||
# 6. Inject environment variables via safe temp file upload
|
||||
inject_env_vars \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}" \
|
||||
"ANTHROPIC_BASE_URL=https://openrouter.ai/api" \
|
||||
"ANTHROPIC_AUTH_TOKEN=${OPENROUTER_API_KEY}" \
|
||||
"ANTHROPIC_API_KEY=" \
|
||||
"CLAUDE_CODE_SKIP_ONBOARDING=1" \
|
||||
"CLAUDE_CODE_ENABLE_TELEMETRY=0" \
|
||||
"PATH=\$HOME/.claude/local/bin:\$HOME/.bun/bin:\$PATH"
|
||||
|
||||
ENV_VARS="
|
||||
export OPENROUTER_API_KEY='${OPENROUTER_API_KEY}'
|
||||
export ANTHROPIC_BASE_URL='https://openrouter.ai/api'
|
||||
export ANTHROPIC_AUTH_TOKEN='${OPENROUTER_API_KEY}'
|
||||
export ANTHROPIC_API_KEY=''
|
||||
export CLAUDE_CODE_SKIP_ONBOARDING='1'
|
||||
export CLAUDE_CODE_ENABLE_TELEMETRY='0'
|
||||
export PATH=\"\$HOME/.claude/local/bin:\$HOME/.bun/bin:\$PATH\"
|
||||
"
|
||||
|
||||
run_in_codespace "$CODESPACE" "cat >> ~/.bashrc << 'ENVEOF'
|
||||
$ENV_VARS
|
||||
ENVEOF"
|
||||
|
||||
# 7. Configure Claude Code settings
|
||||
log_warn "Configuring Claude Code..."
|
||||
|
||||
run_in_codespace "$CODESPACE" "mkdir -p ~/.claude"
|
||||
|
||||
# Create settings.json
|
||||
SETTINGS_JSON="{
|
||||
\"theme\": \"dark\",
|
||||
\"editor\": \"vim\",
|
||||
\"env\": {
|
||||
\"CLAUDE_CODE_ENABLE_TELEMETRY\": \"0\",
|
||||
\"ANTHROPIC_BASE_URL\": \"https://openrouter.ai/api\",
|
||||
\"ANTHROPIC_AUTH_TOKEN\": \"${OPENROUTER_API_KEY}\"
|
||||
},
|
||||
\"permissions\": {
|
||||
\"defaultMode\": \"bypassPermissions\",
|
||||
\"dangerouslySkipPermissions\": true
|
||||
}
|
||||
}"
|
||||
|
||||
run_in_codespace "$CODESPACE" "cat > ~/.claude/settings.json << 'SETTINGSEOF'
|
||||
$SETTINGS_JSON
|
||||
SETTINGSEOF"
|
||||
|
||||
# Create global state file
|
||||
GLOBAL_STATE="{
|
||||
\"hasCompletedOnboarding\": true,
|
||||
\"bypassPermissionsModeAccepted\": true
|
||||
}"
|
||||
|
||||
run_in_codespace "$CODESPACE" "cat > ~/.claude.json << 'STATEEOF'
|
||||
$GLOBAL_STATE
|
||||
STATEEOF"
|
||||
|
||||
# Create empty CLAUDE.md
|
||||
run_in_codespace "$CODESPACE" "touch ~/.claude/CLAUDE.md"
|
||||
# 7. Configure Claude Code settings via shared helper
|
||||
setup_claude_code_config "$OPENROUTER_API_KEY" "upload_file" "run_server"
|
||||
|
||||
echo ""
|
||||
log_info "Setup complete. Opening interactive session..."
|
||||
|
|
|
|||
|
|
@ -31,12 +31,15 @@ fi
|
|||
|
||||
log_info "Codespace created: $CODESPACE"
|
||||
|
||||
# Set CODESPACE_NAME for upload_file/run_server/inject_env_vars helpers
|
||||
CODESPACE_NAME="$CODESPACE"
|
||||
|
||||
# 3. Wait for codespace to be ready
|
||||
wait_for_codespace "$CODESPACE"
|
||||
|
||||
# 4. Install gptme
|
||||
log_warn "Installing gptme..."
|
||||
run_in_codespace "$CODESPACE" "pip install gptme 2>/dev/null || pip3 install gptme"
|
||||
run_server "pip install gptme 2>/dev/null || pip3 install gptme"
|
||||
log_info "gptme installed"
|
||||
|
||||
# 5. Get OpenRouter API key
|
||||
|
|
@ -50,16 +53,9 @@ fi
|
|||
# 6. Get model preference
|
||||
MODEL_ID=$(get_model_id_interactive "openrouter/auto" "gptme") || exit 1
|
||||
|
||||
# 7. Inject environment variables into ~/.bashrc
|
||||
log_warn "Setting up environment variables..."
|
||||
|
||||
ENV_VARS="
|
||||
export OPENROUTER_API_KEY='${OPENROUTER_API_KEY}'
|
||||
"
|
||||
|
||||
run_in_codespace "$CODESPACE" "cat >> ~/.bashrc << 'ENVEOF'
|
||||
$ENV_VARS
|
||||
ENVEOF"
|
||||
# 7. Inject environment variables via safe temp file upload
|
||||
inject_env_vars \
|
||||
"OPENROUTER_API_KEY=${OPENROUTER_API_KEY}"
|
||||
|
||||
echo ""
|
||||
log_info "GitHub Codespace setup completed successfully!"
|
||||
|
|
@ -73,4 +69,4 @@ echo ""
|
|||
sleep 1
|
||||
|
||||
# Launch gptme with model
|
||||
run_in_codespace "$CODESPACE" "source ~/.bashrc && gptme -m openrouter/${MODEL_ID}"
|
||||
run_server "source ~/.bashrc && gptme -m openrouter/${MODEL_ID}"
|
||||
|
|
|
|||
|
|
@ -174,6 +174,57 @@ delete_codespace() {
|
|||
}
|
||||
}
|
||||
|
||||
# Upload a file to codespace via gh codespace cp
|
||||
# Args: $1 = local path
|
||||
# $2 = remote path
|
||||
upload_file() {
|
||||
local local_path="$1"
|
||||
local remote_path="$2"
|
||||
|
||||
if [[ ! -f "$local_path" ]]; then
|
||||
log_error "Local file not found: $local_path"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -z "${CODESPACE_NAME:-}" ]]; then
|
||||
log_error "CODESPACE_NAME not set. Call create_codespace first."
|
||||
return 1
|
||||
fi
|
||||
|
||||
gh codespace cp "$local_path" "${CODESPACE_NAME}:${remote_path}"
|
||||
}
|
||||
|
||||
# Run a command on the codespace (wrapper matching other providers' interface)
|
||||
run_server() {
|
||||
local cmd="$1"
|
||||
|
||||
if [[ -z "${CODESPACE_NAME:-}" ]]; then
|
||||
log_error "CODESPACE_NAME not set. Call create_codespace first."
|
||||
return 1
|
||||
fi
|
||||
|
||||
gh codespace ssh --codespace "$CODESPACE_NAME" -- bash -c "$cmd"
|
||||
}
|
||||
|
||||
# Inject environment variables into shell config
|
||||
# Writes to a temp file and uploads to avoid shell interpolation of values
|
||||
inject_env_vars() {
|
||||
log_warn "Injecting environment variables..."
|
||||
|
||||
local env_temp
|
||||
env_temp=$(mktemp)
|
||||
chmod 600 "${env_temp}"
|
||||
track_temp_file "${env_temp}"
|
||||
|
||||
generate_env_config "$@" > "${env_temp}"
|
||||
|
||||
# Upload and append to .bashrc
|
||||
upload_file "${env_temp}" "/tmp/env_config"
|
||||
run_server "cat /tmp/env_config >> ~/.bashrc && rm /tmp/env_config"
|
||||
|
||||
log_info "Environment variables configured"
|
||||
}
|
||||
|
||||
# Get codespace info
|
||||
# Args: $1 = codespace name
|
||||
get_codespace_info() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue