Skill Trust Decision

LLM Proxy

The skill acts as an unauthenticated local proxy forwarding user API credentials to external LLM providers, with a content-security layer that declares blocking but only logs critical alerts (including credential theft and reverse shell patterns), creating a deceptive security illusion.

Install decision first Source: Manual upload Scanned: Apr 4, 2026
Files 7
Artifacts 25
Violations 4
Findings 8
Most direct threat evidence
Critical Credential Theft
Critical content-blocking disabled — credential exfiltration not prevented

content-filter-rules.json defines CRED-001 (sk-, AKIA-, ghp_, api_key patterns) as severity=critical, but response_actions.critical.block=false. The proxy will log credential-theft attempts but forward the actual request to the upstream LLM provider, meaning stolen API keys go through the proxy.

scripts/content-filter-rules.json:217

Why this conclusion was reached

2/4 dimensions flagged
Block
Declared vs actual capability

4 undeclared or violating capabilities were inferred.

Review
Hidden execution and egress

25 lower-risk artifacts were extracted and still need context.

Block
Attack chain and severe findings

The report includes 5 attack-chain steps and 5 severe findings.

Pass
Dependencies and supply chain hygiene

Dependencies are present but no obvious high-risk issue stands out.

Attack Chain

01
User invokes skill to '启动llm-proxy'

Entry · SKILL.md:17

02
Skill runs llm-proxy-ctl.sh which starts daemon via background process (&), kill/kill -9 port cleanup — shell:WRITE capability used without declaration

Escalation · scripts/llm-proxy-ctl.sh:34

03
Proxy binds to TCP port 18888 on 127.0.0.1 — network:WRITE not declared in SKILL.md

Escalation · scripts/llm-proxy.py:482

04
Attacker sends POST with stolen API key through the proxy (no auth required since block=false)

Escalation · scripts/llm-proxy.py:259

05
CRED-001 fires but block=false; credential exfiltration is only logged, not prevented. Stolen key is forwarded to upstream provider.

Impact · scripts/content-filter-rules.json:217

What drove the risk score up

Undeclared shell execution +15

SKILL.md does not mention subprocess, shell, or process management; llm-proxy-ctl.sh uses kill/kill_by_port

Undeclared network binding +12

SKILL.md does not declare opening a TCP port or running a persistent background service

Auth bypass - no credential verification +18

Proxy forwards user Authorization/API-Key headers to external providers with no auth check; any local process can use the proxy

Critical content rules have block=false +20

response_actions block=false for critical severity — credential exfiltration and reverse shell patterns only logged, not blocked

Doc-to-code behavior mismatch +10

SKILL.md states '严重违规时阻断响应' but code sets block=false for all severity levels including critical

Most important evidence

Critical Credential Theft

Critical content-blocking disabled — credential exfiltration not prevented

content-filter-rules.json defines CRED-001 (sk-, AKIA-, ghp_, api_key patterns) as severity=critical, but response_actions.critical.block=false. The proxy will log credential-theft attempts but forward the actual request to the upstream LLM provider, meaning stolen API keys go through the proxy.

scripts/content-filter-rules.json:217
Set block: true for critical severity in response_actions, or add a hard check in llm-proxy.py before _forward_request() is called.
Critical Credential Theft

API key forwarding without authorization

The proxy blindly forwards the Authorization and X-Api-Key headers from incoming requests directly to upstream LLM providers. Any local process can send requests with arbitrary credentials through this proxy. Combined with block=false on credential detection, a stolen API key can be routed through this proxy.

scripts/llm-proxy.py:259
Add local authentication (e.g., a shared secret header) to validate requests before forwarding credentials.
High Doc Mismatch

Documentation claims blocking, code does not block

SKILL.md states: '严重违规时阻断响应并返回错误' (blocks on serious violations) and README states '内容安全检测仅记录和提醒,不自动拦截(可配置)' — both contradictory. The code sets block=false for all severity levels. This is a doc-to-code mismatch.

SKILL.md:99
Align documentation with actual behavior or change block=false to block=true in response_actions.
High Sensitive Access

Undeclared persistent background service

SKILL.md does not mention that the skill runs a persistent background daemon, opens a TCP port, or manages processes. The llm-proxy-ctl.sh starts a daemon via backgrounding (&) and writes to /tmp/llm-proxy.pid. This is not declared.

scripts/llm-proxy-ctl.sh:34
Declare in SKILL.md that the skill starts a background daemon and manages processes.
High Doc Mismatch

Undeclared shell and process management capabilities

SKILL.md declares no shell execution, but llm-proxy-ctl.sh uses kill, kill -9, lsof, curl, mkdir, and background process management. SKILL.md also declares no filesystem WRITE, but scripts write to ~/.openclaw/logs/ and /tmp/.

scripts/llm-proxy-ctl.sh:1
Declare shell:WRITE in the capability manifest and document process/service management in SKILL.md.
Medium RCE

SIGUSR1 debug handler exposes full thread stacks

llm-proxy.py registers signal.SIGUSR1 which, when triggered, prints full thread stacks including any sensitive data in stack frames. This could leak internal state, credentials in variables, or request content.

scripts/llm-proxy.py:471
Remove the SIGUSR1 debug handler in production code, or restrict it to trusted users only.
Medium Data Exfil

Verbose request/response logging to user-writable directory

All requests and responses (including message content, provider, request_id, status) are written to ~/.openclaw/logs/llm-proxy/proxy-YYYY-MM-DD.jsonl. While Authorization headers are redacted, the response content and full request metadata are logged. This creates a local data trail.

scripts/llm-proxy.py:361
Log only anonymized metadata, not full request/response content. Add .gitignore and warn users about the log directory.
Low Supply Chain

No dependencies declared — no requirements.txt or package.json

The skill uses only Python standard library (json, re, time, os, sys, signal, traceback, uuid, threading, datetime, http.server, socketserver, urllib). No third-party dependencies, which reduces supply chain risk. However, subprocess is not declared as a dependency since it's used in shell scripts.

scripts/llm-proxy.py:1
Document that only Python standard library is required and declare shell access in SKILL.md.

Declared capability vs actual capability

Network Block
Declared NONE
Inferred WRITE
SKILL.md:1 — SKILL.md declares no network access, but the proxy opens TCP port 18888 and makes outbound HTTP requests to 22+ external LLM provider APIs
Shell Block
Declared NONE
Inferred WRITE
llm-proxy-ctl.sh:34,47 — Uses lsof, kill, kill -9, backgrounding python3; SKILL.md makes no mention of subprocess or shell usage
Filesystem Block
Declared NONE
Inferred WRITE
llm-proxy-ctl.sh:35 — mkdir -p for log dirs; llm-proxy.py:89 — writes to ~/.openclaw/logs/
Environment Block
Declared NONE
Inferred READ
llm-proxy.py:34-37 — reads LLMPROXY_CONFIG, LLM_PROXY_PORT, RULES_FILE from os.environ

Suspicious artifacts and egress

Medium External URL
http://127.0.0.1:18888/health

README.md:116

Medium External URL
https://api.your-provider.com/v1

README.md:147

Medium External URL
http://127.0.0.1:18888/your-provider/chat/completions

README.md:156

Medium External URL
https://api.your-provider.com/v1/chat/completions

README.md:157

Medium External URL
http://127.0.0.1:18888/openai/chat/completions

README.md:259

Medium External URL
http://127.0.0.1:18888/bailian/chat/completions

README.md:272

Medium External URL
https://api.groq.com/openai/v1

scripts/llm-proxy-config.json:49

Medium External URL
https://api.cloudflare.com/client/v4/accounts

scripts/llm-proxy-config.json:55

Medium External URL
https://api.deepseek.com/v1

scripts/llm-proxy-config.json:61

Medium External URL
https://api.moonshot.cn/v1

scripts/llm-proxy-config.json:67

Medium External URL
https://open.bigmodel.cn/api/paas/v4

scripts/llm-proxy-config.json:73

Medium External URL
https://api.siliconflow.cn/v1

scripts/llm-proxy-config.json:79

Dependencies and supply chain

PackageVersionSourceKnown vulnNotes
Python standard library only N/A stdlib No Uses only json, re, time, os, sys, signal, threading, http.server, socketserver, urllib — no pip packages needed

File composition

7 files · 1748 lines
Python 1 files · 608 linesMarkdown 2 files · 539 linesJSON 2 files · 412 linesShell 2 files · 189 lines
Files of concern · 6
scripts/llm-proxy.py Python · 608 lines
API key forwarding without authorization · SIGUSR1 debug handler exposes full thread stacks · Verbose request/response logging to user-writable directory · No dependencies declared — no requirements.txt or package.json · [email protected]
scripts/content-filter-rules.json JSON · 248 lines
Critical content-blocking disabled — credential exfiltration not prevented · [email protected]
README.md Markdown · 347 lines
http://127.0.0.1:18888/health · https://api.your-provider.com/v1 · http://127.0.0.1:18888/your-provider/chat/completions · https://api.your-provider.com/v1/chat/completions · http://127.0.0.1:18888/openai/chat/completions · http://127.0.0.1:18888/bailian/chat/completions
scripts/llm-proxy-config.json JSON · 164 lines
https://api.groq.com/openai/v1 · https://api.cloudflare.com/client/v4/accounts · https://api.deepseek.com/v1 · https://api.moonshot.cn/v1 · https://open.bigmodel.cn/api/paas/v4 · https://api.siliconflow.cn/v1 · https://openrouter.ai/api/v1 · https://integrate.api.nvidia.com/v1 · https://coding.dashscope.aliyuncs.com/v1 · https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxin_workshop · https://spark-api.xf-yun.com/v3.5/chat · https://api.minimax.chat/v1 · https://api.lingyiwanwu.com/v1 · https://api.baichuan-ai.com/v1 · https://api.together.xyz/v1 · https://api.fireworks.ai/inference/v1 · https://api.replicate.com/v1
scripts/llm-proxy-ctl.sh Shell · 134 lines
Undeclared persistent background service · Undeclared shell and process management capabilities
SKILL.md Markdown · 192 lines
Documentation claims blocking, code does not block
Other files · llm-proxy-common.sh

Security positives

Content filter rules are comprehensive and well-structured with L1 (malicious command), L2 (sensitive content), and L3 (LLM review) layers
Credential patterns (sk-, AKIA-, ghp_) are detected via regex in the filter rules
Authorization headers are redacted in log entries (***REDACTED***)
API keys in response previews are masked with regex substitution
Proxy binds only to 127.0.0.1 (not exposed to the internet)
Request body size is limited (10MB) to prevent DoS
Uses only Python standard library — no third-party dependencies to compromise
Response data field removed from logs (blocked responses only log alert metadata, not content)
Thread-safe logging with locks prevents log injection
Config keys prefixed with '_' are ignored during loading