Back to skill

Security audit

Stock Batting Zone

Security checks for vulnerabilities and agentic risk

Overview

The skill’s stock-report purpose is clear, but it under-discloses cross-skill credential reuse and can write that credential to a dry-run file.

Review carefully before installing. This skill should be changed to use an explicit credential configured for this skill, avoid reading another skill's authCode, avoid serializing credentials in dry-run files, and avoid executing an unaudited hard-coded external script path unless the user explicitly approves that integration.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/daily_batting.py:360
Finding

Authentication Code Persisted in Plaintext During Dry-Run

Content
View full analysis

Vulnerability Details

File Location: scripts/daily_batting.py, lines 360–371 and 416–426
Vulnerability Type: Plaintext credential exposure
Risk Level: Medium

Vulnerable Code

python
return {
    "task_id": f"daily_batting_{today.replace('-', '')}",
    "task_name": f"每日击球区日报 - {today}",
    "task_result": summary,
    "task_content": content,
    "schedule_task_id": "daily_batting_zone",
    "auth_code": read_auth_code(),
}


def read_auth_code():
    try:
        with open(r"C:\Users\And19\.openclaw\openclaw.json", "r", encoding="utf-8") as f:
            cfg = json.load(f)
        code = cfg.get("skills", {}).get("entries", {}).get("today-task", {}).get("config", {}).get("authCode")
        if code: return code
    except: pass
    return "MISSING"
python
card = build_card(quotes)
log.info(f"Summary: {card['task_result']}")

if args.dry_run:
    with open("daily_dryrun.json", "w", encoding="utf-8") as f:
        json.dump(card, f, ensure_ascii=False, indent=2)
    log.info("[DRY-RUN] saved")
    return 0

Technical Analysis

build_card() unconditionally reads the today-task authentication code from the user's OpenClaw configuration and inserts it into the generated card. This occurs even in dry-run mode, where authentication is unnecessary because no push is performed.

The dry-run branch serializes the complete card—including auth_code—to the predictable plaintext file daily_dryrun.json. The script does not set restrictive permissions, redact the credential, or delete the file afterward. This creates an avoidable persistent copy of a secret outside its original configuration store.

Attack Path

  1. A user or automated process executes:

    bash
    python scripts/daily_batting.py --dry-run
    
  2. build_card() calls read_auth_code().

  3. The script reads the today-task authentication code from C:\Users\And19\.openclaw\openclaw.json.

  4. The authentication code is inserted into the card as `auth_ ...[truncated 960 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove auth_code from build_card() so ordinary card construction never retrieves or embeds a credential.

  2. Add the authentication code only immediately before an actual push:

    python
    card = build_card(quotes)
    
    if args.dry_run:
        with open("daily_dryrun.json", "w", encoding="utf-8") as f:
            json.dump(card, f, ensure_ascii=False, indent=2)
        return 0
    
    push_card = {**card, "auth_code": read_auth_code()}
    ok = push_to_neg1(push_card)
    
  3. Prefer passing the credential to the push component through a protected environment variable, standard input, or another mechanism that does not serialize it to disk.

  4. If a sensitive temporary file is unavoidable, create it with owner-only permissions, keep its lifetime minimal, and guarantee deletion in a finally block.

  5. Add a test asserting that dry-run output never contains auth_code, authCode, or the configured credential value.

  6. Add daily_dryrun.json to ignore rules as defense in depth, while recognizing that ignore rules do not prevent local disclosure.

  7. Delete existing dry-run files and rotate the authentication code if any generated file may have been shared, committed, backed up, or otherwise exposed.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documents or implies code behavior that uses environment access, file I/O, network, and shell capabilities, but it does not declare any explicit tool scope or permissions boundary. This is dangerous because reviewers and runtime policy systems cannot easily enforce least privilege, and a later implementation could overreach or exfiltrate data using undeclared capabilities.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill is designed to automatically push generated content to Huawei's negative-one screen, which is an external transmission/output action, but the description does not present a clear user warning, consent model, or disclosure of what data is sent. This creates a privacy and transparency risk because users may not realize outputs are automatically transmitted to a third-party surface on a schedule.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill reads an authCode from another skill's local configuration file and silently reuses it for its own push operation. This crosses a credential boundary unrelated to stock analysis, enabling unauthorized use of another component's secret and weakening least-privilege isolation between skills.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Reading an authentication code from a local config file without disclosure means the skill accesses sensitive credentials behind the user's back. In the context of a daily stock report, this behavior is not necessary for analysis itself and increases the risk of secret misuse, credential sprawl, and unnoticed cross-skill access.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill delegates report pushing to an external script outside its own codebase, which creates a trust-boundary break and makes behavior dependent on unaudited code at runtime. If that external file is modified or replaced locally, this skill will execute it with the harvested auth code and generated report data.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/daily_batting.py (reported line 380)May include surrounding context.

python
json.dump(card, tmp, ensure_ascii=False, indent=2)
    tmp.close()
    try:
        result = subprocess.run(
            ["python", PUSH_SCRIPT, "--data", tmp.name],
            capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=60,
        )

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The manifest description and the rest of the skill documentation are entirely Chinese-language and do not indicate whether users may opt into another language. This can be a language/locale policy issue when a skill effectively forces one language without explicit opt-in or documented regional justification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.