T09 · Insecure Skill Coding Practices
- Location
scripts/common.py:98- Finding
Proxy credentials exposed through process command-line arguments
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill largely does what it advertises, but it needs Review because it can install global tools, use local browser/API credentials, and send generated content to Feishu with broad triggering and limited confirmation.
Install only if you are comfortable giving this skill Feishu bot-send authority, Product Hunt and optional Firecrawl/API credentials, proxy settings, local SQLite persistence, and possible access to a logged-in browser session for X/Twitter. Prefer dry-run first, avoid authenticated proxy URLs in PROXY_URL on shared machines, install lark-cli yourself from a pinned trusted version, and confirm the target FEISHU_CHAT_ID before allowing automatic sends.
scripts/common.py:98Proxy credentials exposed through process command-line arguments
scripts/setup.py:100Unpinned package installation with global system scope
This second mismatch finding is also valid: the skill claims end-to-end news briefing generation and Feishu delivery, but parts of the behavior are delegated to local file aggregation, database maintenance, and external tooling rather than being transparently represented in the top-level contract. Hidden persistence and external side effects increase risk because they create stateful behavior and outbound communication beyond what a casual description suggests.
This second mismatch finding is also valid: the skill claims end-to-end news briefing generation and Feishu delivery, but parts of the behavior are delegated to local file aggregation, database maintenance, and external tooling rather than being transparently represented in the top-level contract. Hidden persistence and external side effects increase risk because they create stateful behavior and outbound communication beyond what a casual description suggests.
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.
# ── 环境 ──
load_env()
DATE = os.environ.get("AI_DAILY_DATE", os.popen("date +%Y-%m-%d").read().strip())
DEFAULT_OUTPUT_DIR = f"/tmp/ai-daily-briefing/{DATE}"
# ── 板块配置 ──
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.
def collect_github(max_items):
"""从 GitHub Search API 采集。"""
week_ago = os.popen("date -d '7 days ago' +%Y-%m-%d").read().strip()
data = curl_json(
f"https://api.github.com/search/repositories?q=created:>{week_ago}+stars:>50+topic:ai"
f"&sort=stars&order=desc&per_page=10"
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.
def collect_github(max_items):
"""从 GitHub Search API 采集。"""
week_ago = os.popen("date -d '7 days ago' +%Y-%m-%d").read().strip()
data = curl_json(
f"https://api.github.com/search/repositories?q=created:>{week_ago}+stars:>50+topic:ai"
f"&sort=stars&order=desc&per_page=10"
Passing {**os.environ, "OPENCLI_CDP_ENDPOINT": cdp} leaks the full parent environment into a browser automation child process. In an agent runtime, that environment may include tokens, proxy credentials, and other secrets that the child tool or any connected browser/plugin could access, making this materially dangerous.
try:
r = subprocess.run(
["opencli", "web", "fetch", "https://x.com/home"],
capture_output=True, text=True, env={**os.environ, "OPENCLI_CDP_ENDPOINT": cdp}
)
html = r.stdout
if not html or len(html) < 1000:
This second opencli invocation repeats the same full-environment forwarding pattern. Because the child process performs browser automation, exposing all environment variables significantly raises the risk of credential leakage and cross-capability abuse.
try:
r = subprocess.run(
["opencli", "web", "fetch", "https://x.com/search?q=agent+framework+AI"],
capture_output=True, text=True, env={**os.environ, "OPENCLI_CDP_ENDPOINT": cdp}
)
html = r.stdout
if not html or len(html) < 1000:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def load_env():
"""从 ~/.openclaw/.env 加载环境变量。"""
env_file = os.path.expanduser("~/.openclaw/.env")
if not os.path.exists(env_file):
return
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def load_env():
"""从 ~/.openclaw/.env 加载环境变量。"""
env_file = os.path.expanduser("~/.openclaw/.env")
if not os.path.exists(env_file):
return
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def load_env():
"""从 ~/.openclaw/.env 加载环境变量。"""
env_file = os.path.expanduser("~/.openclaw/.env")
if not os.path.exists(env_file):
return
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
if shutil.which("opencli"):
out = subprocess.run(
["opencli", "doctor"],
capture_output=True, text=True, env={**os.environ, "OPENCLI_CDP_ENDPOINT": "http://127.0.0.1:9222"}
).stdout
if "Extension: connected" in out:
_ok("opencli 扩展已连接")
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
if shutil.which("opencli"):
out = subprocess.run(
["opencli", "doctor"],
capture_output=True, text=True, env={**os.environ, "OPENCLI_CDP_ENDPOINT": "http://127.0.0.1:9222"}
).stdout
if "Extension: connected" in out:
_ok("opencli 扩展已连接")
Using shell=True for install_cmd is a classic tool-parameter abuse pattern because it delegates command parsing to the shell and allows broad execution semantics. In a setup script that may be run with elevated privileges and invokes package managers/npm, this materially increases the blast radius of any future input contamination, environment manipulation, or code reuse mistake.
"""尝试自动安装工具,返回是否成功。"""
print(f" 尝试自动安装 {name}...")
try:
subprocess.run(install_cmd, shell=True, check=True, capture_output=True)
if check_cmd and not shutil.which(check_cmd):
return False
return True
The script can send aggregated content to Feishu automatically using environment-provided identifiers, without an explicit user-facing warning in this execution path. Because the content comes from multiple external sources and may include unreviewed titles, descriptions, and URLs, this creates a real exfiltration/transmission risk to an external service.
The code injects untrusted stderr from an external subprocess directly into a Feishu outbound message. If the CLI or upstream service returns attacker-influenced content, the script can relay misleading text, sensitive diagnostics, internal identifiers, or formatting payloads to a user, creating an output-injection and information-disclosure issue.
# 发送失败,私信用户
print(f"Card send failed: {result.stderr}")
if feishu_open_id:
subprocess.run(
["lark-cli", "--profile", feishu_app_id, "--as", "bot",
"im", "+messages-send",
"--user-id", feishu_open_id,
The skill requests and describes capabilities equivalent to environment access, filesystem read/write, network access, and shell execution, but it does not declare any explicit tool scope such as permissions or allowed-tools. This weakens policy enforcement and reviewability: an agent may execute broader actions than users or platform controls expect, including sending messages, accessing secrets, and writing persistent state.
The trigger conditions are broad enough to activate on common requests about AI news, daily briefings, or AI updates. Overbroad triggering is risky because it can cause the agent to invoke a capability-heavy skill unexpectedly, leading to network collection, filesystem writes, or external message sending when the user only intended a simple conversational answer.
The skill description and operational instructions are written to generate the briefing in Chinese-oriented formatting and messaging, including '生成每日 AI 资讯简报' and '中英文自动加空格', with no indication that users may choose another language or locale. This creates a locale/language policy concern because the skill appears to impose a specific language behavior without explicit user opt-in.
This code file contains user-facing natural-language documentation and CLI help context in Chinese only, such as the module docstring describing usage and environment variables. That imposes a specific language on users without opt-in or an alternative locale, which matches the language/locale policy violation category.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if fc_key:
try:
import json as _json
r = subprocess.run(
[
"curl", "-s", "--max-time", "20",
"-X", "POST", "https://api.firecrawl.dev/v1/scrape",
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
if fc_key:
try:
import json as _json
r = subprocess.run(
[
"curl", "-s", "--max-time", "20",
"-X", "POST", "https://api.firecrawl.dev/v1/scrape",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
r = subprocess.run(
[
"curl", "-s", "--max-time", "20",
"-X", "POST", "https://api.firecrawl.dev/v1/scrape",
"-H", "Content-Type: application/json",
"-H", f"Authorization: Bearer {fc_key}",
"-d", _json.dumps({"url": "https://www.anthropic.com/news", "formats": ["markdown"]})
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
try:
query_json = json.dumps({"query": f"{{ {SECTIONS['producthunt']['query']} }}"})
r = subprocess.run(
["curl", "-s", "--max-time", "15",
"-X", "POST", "https://api.producthunt.com/v2/api/graphql",
"-H", f"Authorization: Bearer {ph_token}",
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
try:
query_json = json.dumps({"query": f"{{ {SECTIONS['producthunt']['query']} }}"})
r = subprocess.run(
["curl", "-s", "--max-time", "15",
"-X", "POST", "https://api.producthunt.com/v2/api/graphql",
"-H", f"Authorization: Bearer {ph_token}",
The manifest describes a news briefing collector, but the implementation includes undeclared X/Twitter scraping through browser automation. This capability mismatch is dangerous in an agent skill because it hides materially more powerful behavior than users would reasonably expect, increasing the chance of over-collection or privacy-impacting browser access.
No suspicious patterns detected.