Back to skill

Security audit

A-stock-report

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed automated stock-report sender, but it needs review because it auto-posts financial guidance with secrets and uses insecure shared temporary and lock files.

Install only if you control the host and WeCom destination, understand that reports and investment-related suggestions can be posted automatically, and can protect /workspace/.env. Before production use, replace curl subprocess sending with an in-process HTTPS client, move all handoff and lock files into a private 0700 runtime directory with atomic creation, avoid sourcing a broad .env in cron, and review the configured cron jobs and outbound domains.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_send_lib.py:31
Finding

WeCom Webhook Secret Exposed Through Subprocess Command-Line Arguments

Content
View full analysis
str: """Read webhook URL from environment; raise RuntimeError if absent.""" key = os.environ.get("WECOM_WEBHOOK_KEY", "") if not key: raise RuntimeError("WECOM_WEBHOOK_KEY environment variable not set") return f"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={key.strip()}" def wx(text: str, max_retries: int = 2) -> int: """Send a WeCom message with automatic retries.""" payload = json.dumps( {"msgtype": "text", "text": {"content": text}}, ensure_ascii=False, ) for attempt in range(max_retries + 1): try: url = get_webhook_url() except RuntimeError as _e: print(f"[{_ts()}] [WX] webhook URL retrieval failed: {_e}") return -1 r = subprocess.run( ["curl", "-s", "-X", "POST", url, "-H", "Content-Type: application/json", "-d", "@-"], input=payload.encode("utf-8"), capture_output=True, ) ``` The same vulnerable pattern is independently duplicated in `scripts/send_evening_report.py:100-115`. ### Technical Analysis The WeCom webhook key is embedded in a URL and passed directly to `curl` as a command-line argument. While the report body is correctly passed through standard input, the complete webhook URL—including the credential in its `key` query parameter—appears in the child process's argument vector. While `curl` is running, the URL may be observable through process inspection mechanisms such as: - `/proc//cmdline` - Process-monitoring utilities - System telemetry or command-line audit logs - Container or host-level monitoring agents Access depends on the host's process-visibility configuration, user separation, and monitoring permissions. Nevertheless ...[truncated 1620 chars]
Remediation
View remediation
int: try: url = get_webhook_url() except RuntimeError as exc: print(f"[WX] Webhook URL retrieval failed: {exc}") return -1 payload = {"msgtype": "text", "text": {"content": text}} for attempt in range(max_retries + 1): try: response = requests.post(url, json=payload, timeout=10) response.raise_for_status() if response.json().get("errcode") == 0: return 0 except (requests.RequestException, ValueError) as exc: print(f"[WX] Request failed: {type(exc).__name__}") return -1 ``` 2. Refactor `scripts/send_evening_report.py` to use the hardened shared helper instead of maintaining a duplicate implementation. 3. Ensure exceptions and logs never print the complete webhook URL. 4. Restrict environment-variable and process visibility at the host or container boundary as defense in depth. 5. Rotate the existing WeCom webhook key if there is any indication that command-line monitoring or process telemetry has retained it. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/send_evening_report.py:778
Finding

Predictable Shared Temporary Files Permit Trusted Report Content Injection

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_lock.py:35
Finding

Non-Atomic Predictable Lock and Output Files Enable Symlink and Race Attacks

Content
View full analysis
bool: if os.path.exists(path): info = _read_lock(path) if info is not None: pid, prev_owner, created = info age = time.time() - created if _pid_alive(pid) and age < ttl: print( f"[LOCK] Another instance is running " f"(pid={pid} {prev_owner}); exiting.", file=sys.stderr, ) return False try: os.remove(path) except OSError: pass with open(path, "w") as f: f.write(f"{os.getpid()}\n{owner or 'unknown'}\n{time.time()}\n") return True def unlock(path: str): if os.path.exists(path): try: os.remove(path) except OSError: pass ``` Related predictable writes include: ```python with open("/tmp/evening_data.json", "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) ``` and: ```python out_path = "/tmp/morning_data.json" with open(out_path, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis The locking algorithm performs path existence checks, reads, deletion, and recreation as separate filesystem operations. This creates check-time-to-use windows in which another process can change the pathname. ...[truncated 2915 chars]
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (110)

Tainted flow: 'req' from os.environ.get (line 102, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/collect_evening_data.py (reported line 103)May include surrounding context.

python
try:
        url = f"https://qt.gtimg.cn/q={','.join(imap.values())}"
        req = _ur.Request(url, headers={"User-Agent": "Mozilla/5.0"})
        with _ur.urlopen(req, timeout=10) as r:
            raw = r.read().decode("gbk", errors="replace")
        result = []
        for line in raw.strip().split("\n"):

Tainted flow: 'req' from os.environ.get (line 493, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/collect_evening_data.py (reported line 223)May include surrounding context.

python
try:
            req = _ur.Request("https://qt.gtimg.cn/q=sh000001,sz399001",
                              headers={"User-Agent": "Mozilla/5.0"})
            with _ur.urlopen(req, timeout=8) as r:
                raw = r.read().decode("gbk", errors="replace")
            sh = sz = 0.0
            for line in raw.strip().split("\n"):

Tainted flow: 'req' from os.environ.get (line 493, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/collect_evening_data.py (reported line 446)May include surrounding context.

python
try:
            req = _ur.Request("https://qt.gtimg.cn/q=sh000001,sz399001",
                              headers={"User-Agent": "Mozilla/5.0"})
            with _ur.urlopen(req, timeout=8) as r:
                raw = r.read().decode("gbk", errors="replace")
            sh = sz = 0.0
            for line in raw.strip().split("\n"):

Tainted flow: 'req' from os.environ.get (line 493, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/collect_evening_data.py (reported line 497)May include surrounding context.

python
try:
            req = _ur.Request("https://qt.gtimg.cn/q=sh000001,sz399001",
                              headers={"User-Agent": "Mozilla/5.0"})
            with _ur.urlopen(req, timeout=8) as r:
                raw = r.read().decode("gbk", errors="replace")
            sh = sz = 0.0
            for line in raw.strip().split("\n"):

Tainted flow: 'url' from os.environ.get (line 793, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/collect_evening_data.py (reported line 796)May include surrounding context.

python
url = f"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={key.strip()}"
    payload = json.dumps({"msgtype": "text", "text": {"content": text}}, ensure_ascii=False)
    for attempt in range(max_retries + 1):
        r = _req.post(url, headers={"Content-Type": "application/json"},
                      data=payload.encode("utf-8"), timeout=10)
        try:
            errcode = r.json().get("errcode", -1)

Tainted flow: 'req' from os.environ.get (line 82, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/collect_morning_data.py (reported line 83)May include surrounding context.

python
"X-Claw-Trace-Id": trace_id,
    }
    req = urllib.request.Request(url, data=payload, headers=headers, method="POST")
    with urllib.request.urlopen(req, timeout=30) as resp:
        return json.loads(resp.read().decode("utf-8"))

# ════════════════════════════════════════════════════════════

Tainted flow: 'req' from os.environ.get (line 82, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/collect_morning_data.py (reported line 97)May include surrounding context.

python
req = urllib.request.Request(
            "https://qt.gtimg.cn/q=usDJI,usINX,usIXIC",
            headers={"User-Agent": "Mozilla/5.0"})
        with urllib.request.urlopen(req, timeout=10) as r:
            raw = r.read().decode("gbk", errors="replace")
        for line in raw.strip().split("\n"):
            f = line.lstrip("v_").split("~")

Tainted flow: 'req' from os.environ.get (line 82, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/collect_morning_data.py (reported line 263)May include surrounding context.

python
req = urllib.request.Request(
            "https://qt.gtimg.cn/q=usDJI,usINX,usIXIC",
            headers={"User-Agent": "Mozilla/5.0"})
        with urllib.request.urlopen(req, timeout=10) as r:
            raw = r.read().decode("gbk", errors="replace")
        for line in raw.strip().split("\n"):
            f = line.lstrip("v_").split("~")

Tainted flow: 'headers' from os.environ.get (line 39, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/send_close_summary.py (reported line 50)May include surrounding context.

python
"X-Claw-Trace-Id": _secrets.token_hex(32),
    }
    try:
        r = _req2.post(
            "https://openapi.iwencai.com/v1/query2data",
            headers=headers,
            json={"query": query, "page": "1", "limit": "50", "is_cache": "1", "expand_index": "true"},

Tainted flow: 'headers' from os.environ.get (line 39, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/send_close_summary.py (reported line 272)May include surrounding context.

python
'User-Agent': 'Mozilla/5.0',
            'Referer': 'https://data.eastmoney.com',
        }
        r = requests.get(
            'https://datacenter-web.eastmoney.com/api/data/v1/get',
            params=params, headers=headers, timeout=10
        )

Tainted flow: 'headers' from os.environ.get (line 51, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/send_evening_report.py (reported line 70)May include surrounding context.

python
"expand_index": "true",
    }
    try:
        r = requests.post(
            "https://openapi.iwencai.com/v1/query2data",
            headers=headers, json=payload, timeout=timeout)
        if r.status_code == 200:

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documents external scraping against third-party market data endpoints and explicitly discusses anti-bot evasion tactics such as using full browser User-Agent strings to avoid 403 responses. While not inherently malicious, undeclared outbound collection and request masquerading increase the security and compliance risk because agents may perform network activity beyond user expectations and interact with brittle or restricted endpoints.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill documents external scraping against third-party market data endpoints and explicitly discusses anti-bot evasion tactics such as using full browser User-Agent strings to avoid 403 responses. While not inherently malicious, undeclared outbound collection and request masquerading increase the security and compliance risk because agents may perform network activity beyond user expectations and interact with brittle or restricted endpoints.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill documents external scraping against third-party market data endpoints and explicitly discusses anti-bot evasion tactics such as using full browser User-Agent strings to avoid 403 responses. While not inherently malicious, undeclared outbound collection and request masquerading increase the security and compliance risk because agents may perform network activity beyond user expectations and interact with brittle or restricted endpoints.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill documents external scraping against third-party market data endpoints and explicitly discusses anti-bot evasion tactics such as using full browser User-Agent strings to avoid 403 responses. While not inherently malicious, undeclared outbound collection and request masquerading increase the security and compliance risk because agents may perform network activity beyond user expectations and interact with brittle or restricted endpoints.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The skill documents external scraping against third-party market data endpoints and explicitly discusses anti-bot evasion tactics such as using full browser User-Agent strings to avoid 403 responses. While not inherently malicious, undeclared outbound collection and request masquerading increase the security and compliance risk because agents may perform network activity beyond user expectations and interact with brittle or restricted endpoints.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The skill documents external scraping against third-party market data endpoints and explicitly discusses anti-bot evasion tactics such as using full browser User-Agent strings to avoid 403 responses. While not inherently malicious, undeclared outbound collection and request masquerading increase the security and compliance risk because agents may perform network activity beyond user expectations and interact with brittle or restricted endpoints.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The skill documents external scraping against third-party market data endpoints and explicitly discusses anti-bot evasion tactics such as using full browser User-Agent strings to avoid 403 responses. While not inherently malicious, undeclared outbound collection and request masquerading increase the security and compliance risk because agents may perform network activity beyond user expectations and interact with brittle or restricted endpoints.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill documents external scraping against third-party market data endpoints and explicitly discusses anti-bot evasion tactics such as using full browser User-Agent strings to avoid 403 responses. While not inherently malicious, undeclared outbound collection and request masquerading increase the security and compliance risk because agents may perform network activity beyond user expectations and interact with brittle or restricted endpoints.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The skill documents external scraping against third-party market data endpoints and explicitly discusses anti-bot evasion tactics such as using full browser User-Agent strings to avoid 403 responses. While not inherently malicious, undeclared outbound collection and request masquerading increase the security and compliance risk because agents may perform network activity beyond user expectations and interact with brittle or restricted endpoints.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The skill heavily documents loading secrets from .env files and repeatedly references environment-key handling, command patterns using source .env, and path overrides for env files. In an agent setting, normalizing secret-file access as part of operation increases the chance that the agent reads, exposes, or mishandles credentials beyond the minimum required task.

Content

Scanner excerpt · SKILL.md (reported line 72)May include surrounding context.

md
- [v3.3.0 — 财经要闻段"任务定位"协议:防"盘面数据"冒充"要闻"](knowledge/changelog/v3.3.0.md) — 2026-06-11 晚
- [v3.2.9 — 3 个 dispatcher 任务 skills 字段清理](knowledge/changelog/v3.2.9.md) — 2026-06-11 下午
- [v3.2.8 — 收盘小结格式对齐:4 处拼接 bug](knowledge/changelog/v3.2.8.md) — 2026-06-11
- [v3.2.7 — .env 路径根除:8 脚本多路径回退](knowledge/changelog/v3.2.7.md) — 2026-06-10 下午
- [v3.2.6 — 双副本根除 + jobs.json 隐藏运行时副本修复](knowledge/changelog/v3.2.6.md) — 2026-06-10 上午
- [v3.2.5 — 盘中预警 cron prompt 纯 bash 化](knowledge/changelog/v3.2.5.md) — 2026-06-09 深夜
- [v3.2.4 — 文档补全:明示 knowledge/ 被 clawhub publish 上传](knowledge/changelog/v3.2.4.md) — 2026-06-09 晚

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 106)May include surrounding context.

md
| `collect_morning_data.py` | `IWENCAI_API_KEY`(A50 期货问财查询用)|

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 182)May include surrounding context.

md
| `collect_morning_data.py` | `IWENCAI_API_KEY`(A50 期货问财查询用)|

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 109)May include surrounding context.

md
| `send_evening_report.py` | `WECOM_WEBHOOK_KEY`, `IWENCAI_API_KEY` |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 301)May include surrounding context.

md
| `send_evening_report.py` | `WECOM_WEBHOOK_KEY`, `IWENCAI_API_KEY` |

Static analysis

No suspicious patterns detected.