fix: Eliminate heredoc injection, eval, and API key exposure (#108)

- Replace unquoted heredocs with printf + json_escape for all JSON
  config files containing credentials (8 cloud providers + shared lib)
- Replace eval with printf -v for safe indirect variable assignment
- Move RunPod API key from URL query param to api-key header

Fixes #104, Fixes #105, Fixes #106

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:
A 2026-02-09 11:19:34 -08:00 committed by GitHub
parent c0a840ec3a
commit a24dc101e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 14 additions and 94 deletions

View file

@ -81,11 +81,7 @@ ensure_binarylane_token() {
return 1
fi
mkdir -p "$config_dir"
cat > "$config_file" << EOF
{
"api_token": "$api_token"
}
EOF
printf '{\n "api_token": "%s"\n}\n' "$(json_escape "$api_token")" > "$config_file"
chmod 600 "$config_file"
log_info "API token saved to $config_file"
}

View file

@ -74,11 +74,7 @@ _save_fly_token() {
local config_dir="$HOME/.config/spawn"
local config_file="$config_dir/fly.json"
mkdir -p "$config_dir"
cat > "$config_file" << EOF
{
"token": "$token"
}
EOF
printf '{\n "token": "%s"\n}\n' "$(json_escape "$token")" > "$config_file"
chmod 600 "$config_file"
}

View file

@ -58,26 +58,7 @@ GATEWAY_TOKEN=$(openssl rand -hex 16)
OPENCLAW_CONFIG_TEMP=$(mktemp)
chmod 600 "$OPENCLAW_CONFIG_TEMP"
cat > "$OPENCLAW_CONFIG_TEMP" << EOF
{
"env": {
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}"
},
"gateway": {
"mode": "local",
"auth": {
"token": "${GATEWAY_TOKEN}"
}
},
"agents": {
"defaults": {
"model": {
"primary": "openrouter/${MODEL_ID}"
}
}
}
}
EOF
printf '{\n "env": {\n "OPENROUTER_API_KEY": "%s"\n },\n "gateway": {\n "mode": "local",\n "auth": {\n "token": "%s"\n }\n },\n "agents": {\n "defaults": {\n "model": {\n "primary": "openrouter/%s"\n }\n }\n }\n}\n' "$(json_escape "${OPENROUTER_API_KEY}")" "$(json_escape "${GATEWAY_TOKEN}")" "$(json_escape "${MODEL_ID}")" > "$OPENCLAW_CONFIG_TEMP"
upload_file "$OPENCLAW_CONFIG_TEMP" "/root/.openclaw/openclaw.json"
rm "$OPENCLAW_CONFIG_TEMP"

View file

@ -159,12 +159,7 @@ print(d.get('api_secret', ''))
log_info "API credentials validated"
mkdir -p "$config_dir"
cat > "$config_file" << EOF
{
"api_client_id": "$client_id",
"api_secret": "$secret"
}
EOF
printf '{\n "api_client_id": "%s",\n "api_secret": "%s"\n}\n' "$(json_escape "$client_id")" "$(json_escape "$secret")" > "$config_file"
chmod 600 "$config_file"
log_info "API credentials saved to $config_file"
}

View file

@ -170,14 +170,9 @@ for k in ('application_key','application_secret','consumer_key','project_id'):
local config_dir
config_dir=$(dirname "${config_file}")
mkdir -p "${config_dir}"
cat > "${config_file}" << EOF
{
"application_key": "${app_key}",
"application_secret": "${app_secret}",
"consumer_key": "${consumer_key}",
"project_id": "${project_id}"
}
EOF
printf '{\n "application_key": "%s",\n "application_secret": "%s",\n "consumer_key": "%s",\n "project_id": "%s"\n}\n' \
"$(json_escape "${app_key}")" "$(json_escape "${app_secret}")" \
"$(json_escape "${consumer_key}")" "$(json_escape "${project_id}")" > "${config_file}"
chmod 600 "${config_file}"
log_info "OVHcloud credentials saved to ${config_file}"
return 0

View file

@ -108,11 +108,7 @@ ensure_railway_token() {
# Save to config file
export RAILWAY_TOKEN="$token"
mkdir -p "$config_dir"
cat > "$config_file" << EOF
{
"token": "$token"
}
EOF
printf '{\n "token": "%s"\n}\n' "$(json_escape "$token")" > "$config_file"
chmod 600 "$config_file"
log_info "Token saved to $config_file"
}

View file

@ -45,7 +45,8 @@ print(json.dumps({'query': q}))
curl -s -X POST \
-H "Content-Type: application/json" \
"${RUNPOD_GRAPHQL_URL}?api_key=${RUNPOD_API_KEY}" \
-H "api-key: ${RUNPOD_API_KEY}" \
"${RUNPOD_GRAPHQL_URL}" \
-d "${body}"
}

View file

@ -992,7 +992,7 @@ _update_retry_interval() {
current_interval="${max_interval}"
fi
eval "${interval_var}=${current_interval}"
printf -v "${interval_var}" '%s' "${current_interval}"
}
# Helper to extract HTTP status code and response body from curl output
@ -1520,22 +1520,7 @@ setup_claude_code_config() {
# Create settings.json
local settings_json
settings_json=$(cat << EOF
{
"theme": "dark",
"editor": "vim",
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "0",
"ANTHROPIC_BASE_URL": "https://openrouter.ai/api",
"ANTHROPIC_AUTH_TOKEN": "${openrouter_key}"
},
"permissions": {
"defaultMode": "bypassPermissions",
"dangerouslySkipPermissions": true
}
}
EOF
)
settings_json=$(printf '{\n "theme": "dark",\n "editor": "vim",\n "env": {\n "CLAUDE_CODE_ENABLE_TELEMETRY": "0",\n "ANTHROPIC_BASE_URL": "https://openrouter.ai/api",\n "ANTHROPIC_AUTH_TOKEN": "%s"\n },\n "permissions": {\n "defaultMode": "bypassPermissions",\n "dangerouslySkipPermissions": true\n }\n}\n' "$(json_escape "${openrouter_key}")")
upload_config_file "${upload_callback}" "${run_callback}" "${settings_json}" "~/.claude/settings.json"
# Create .claude.json global state
@ -1593,27 +1578,7 @@ setup_openclaw_config() {
# Create openclaw.json config
local openclaw_json
openclaw_json=$(cat << EOF
{
"env": {
"OPENROUTER_API_KEY": "${openrouter_key}"
},
"gateway": {
"mode": "local",
"auth": {
"token": "${gateway_token}"
}
},
"agents": {
"defaults": {
"model": {
"primary": "openrouter/${model_id}"
}
}
}
}
EOF
)
openclaw_json=$(printf '{\n "env": {\n "OPENROUTER_API_KEY": "%s"\n },\n "gateway": {\n "mode": "local",\n "auth": {\n "token": "%s"\n }\n },\n "agents": {\n "defaults": {\n "model": {\n "primary": "openrouter/%s"\n }\n }\n }\n}\n' "$(json_escape "${openrouter_key}")" "$(json_escape "${gateway_token}")" "$(json_escape "${model_id}")")
upload_config_file "${upload_callback}" "${run_callback}" "${openclaw_json}" "~/.openclaw/openclaw.json"
}

View file

@ -118,12 +118,7 @@ print(d.get('password', ''))
local config_dir
config_dir=$(dirname "${config_file}")
mkdir -p "${config_dir}"
cat > "${config_file}" << EOF
{
"username": "${username}",
"password": "${password}"
}
EOF
printf '{\n "username": "%s",\n "password": "%s"\n}\n' "$(json_escape "${username}")" "$(json_escape "${password}")" > "${config_file}"
chmod 600 "${config_file}"
log_info "Credentials saved to ${config_file}"
}