Back to skill

Security audit

幼儿园思维课程体系

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local worksheet generator, with ordinary caution needed around child roster data and generated CSV files.

Install only if you are comfortable with a local Python skill that creates worksheet files and may store child names, IDs, scores, and progress notes in local outputs. Prefer --no-name or pseudonyms for class rosters, avoid unnecessary personal details, and treat generated _summary.csv files cautiously until CSV escaping/formula neutralization is fixed.

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/batch_roster.py:160
Finding

CSV Formula Injection in Batch Roster Summary

Content
View full analysis

Vulnerability Details

File Location: scripts/batch_roster.py:160-163
Vulnerability Type: CSV formula injection and improper CSV serialization
Risk Level: Medium

Vulnerable Code

python
(out_dir / "_summary.csv").write_text(
    "\n".join(["index,name,status,html"] + [
        f"{x['index']},{x['name']},{x['status']},{x['html']}" for x in summary["students"]
    ]), encoding="utf-8-sig")

Technical Analysis

Student names are read from a user-supplied CSV or JSON roster and copied directly into _summary.csv. The output is assembled through string interpolation rather than a CSV serializer.

If a name starts with a spreadsheet formula prefix such as =, +, -, or @, spreadsheet software may interpret it as a formula when the generated summary is opened. For example, a roster could contain:

text
=HYPERLINK("https://example.invalid","Open")

The implementation also fails to quote commas, double quotes, carriage returns, and line breaks. These characters can corrupt the CSV structure or inject additional rows and columns.

Attack Path

  1. An attacker creates or modifies a roster accepted by --roster.
  2. A student name is set to a formula-prefixed value or a value containing CSV control characters.
  3. A teacher runs scripts/batch_roster.py with the crafted roster.
  4. The untrusted value is written verbatim to _summary.csv.
  5. The teacher opens the generated file in spreadsheet software.
  6. Depending on the spreadsheet application's security configuration, the value is evaluated as a formula or manipulates the apparent CSV structure.

Impact Assessment

Exploitation does not grant privileges to the Python process itself. The impact occurs in the context of the user opening the generated CSV with spreadsheet software.

Possible consequences include:

  • Display of deceptive links or misleading spreadsheet content.
  • Corruption or manipulation of rows ...[truncated 396 chars]
Remediation
View remediation

Remediation Suggestions

  1. Generate _summary.csv with Python's csv.writer rather than manually concatenating fields. This correctly handles commas, double quotes, carriage returns, and line breaks.

  2. Neutralize spreadsheet formula prefixes in every untrusted textual field. If a value begins with =, +, -, or @, prefix it with an apostrophe or apply another mitigation appropriate for supported spreadsheet applications.

  3. Apply formula neutralization after trimming relevant leading whitespace, since some spreadsheet applications may interpret formulas preceded by whitespace or control characters.

  4. Treat all roster-derived fields as untrusted, including names and student identifiers. Apply the same protection if additional fields are later added to the summary.

  5. Add regression tests covering:

    • Formula-prefixed names.
    • Names containing commas and double quotes.
    • Names containing CR/LF characters.
    • Unicode names.
    • Empty names.

A hardened implementation could use:

python
import csv

def safe_csv_cell(value):
    value = str(value)
    check = value.lstrip()
    if check.startswith(("=", "+", "-", "@")):
        return "'" + value
    return value

with (out_dir / "_summary.csv").open(
    "w", encoding="utf-8-sig", newline=""
) as f:
    writer = csv.writer(f)
    writer.writerow(["index", "name", "status", "html"])
    for item in summary["students"]:
        writer.writerow([
            item["index"],
            safe_csv_cell(item["name"]),
            safe_csv_cell(item["status"]),
            safe_csv_cell(item["html"]),
        ])
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (34)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SHIP_REPORT.md (reported line 45)May include surrounding context.

md
| 压缩包不含 __pycache__ | ✅ | — |
| 压缩包不含 .pyc | ✅ | — |
| 压缩包不含 .pyo | ✅ | — |
| 压缩包不含 .env | ✅ | — |
| 压缩包不含 .git | ✅ | — |
| 压缩文件数 ≤ 200(实际 26) | ✅ | — |

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
| 压缩包不含 __pycache__ | ✅ | — |
| 压缩包不含 .pyc | ✅ | — |
| 压缩包不含 .pyo | ✅ | — |
| 压缩包不含 .env | ✅ | — |
| 压缩包不含 .git | ✅ | — |
| 压缩文件数 ≤ 200(实际 26) | ✅ | — |

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose is worksheet generation, but the documentation also describes preflight/test scripts that inspect project files, scan scripts for compliance patterns, validate zip contents, and generate shipping reports. Even if intended for packaging, this is a meaningful behavior expansion beyond the user-facing description and can cause an agent to run broader file-inspection workflows than a user would reasonably expect.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
assets/icon.png ← Skill 图标

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/preflight.py (reported line 200)May include surrounding context.

python
f"顶层含: {[n for n in names if '/' not in n]}")

            # 不允许敏感文件
            for bad in ("__pycache__", ".pyc", ".pyo", ".env", ".git"):
                hits = [n for n in names if bad in n]
                chk(f"压缩包不含 {bad}", not hits, f"命中: {hits[:3]}" if hits else "")

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The example trigger phrases are extremely broad, natural-language requests that overlap with ordinary parenting and education queries. In an agent/skill platform, this can cause accidental invocation or overmatching, leading the skill to activate in contexts the user did not explicitly intend, which is a prompt-routing and scope-control weakness rather than a code-execution flaw.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README explicitly supports batch processing of a class roster CSV, which implies handling children's names and potentially other student data, but provides no privacy, retention, minimization, or safe-storage guidance. In a child-focused educational context, omission of data-handling warnings increases the risk of collecting or exporting sensitive student information without appropriate safeguards.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
76% confidence
Finding

The skill declares operational capabilities such as running Python scripts and reading/writing files, but it does not define an explicit tool scope like allowed-tools or permissions. That gap can let a host agent over-grant shell, file, or even network access based on inferred behavior rather than a least-privilege contract, increasing the blast radius if the skill or surrounding code is modified later.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The invocation examples and trigger table include generic phrases such as “测一下”, “从哪开始”, “怎么教”, “给孩子做”, and the rule says the skill triggers whenever an early-childhood object and a thinking-related intent co-occur. These are broad everyday phrases that could cause unintended activation for general parenting or education conversations rather than explicit requests for this worksheet-generation skill.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The template explicitly collects a child's name, level, dates, accuracy, weaknesses, and mistake examples, which creates an identifiable educational profile for a minor. Because the file provides no privacy notice, minimization guidance, retention limits, or storage/handling instructions, users may store sensitive child data insecurely or share it unintentionally.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger list includes many generic educational terms such as '幼儿', '思维', '图形', '空间', and 'classification' that are likely to match ordinary user requests unrelated to this specific skill. This can cause unintended auto-activation or over-selection of the skill, which is a policy and routing safety issue because it may intercept user queries too broadly and degrade correct tool choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The entire curriculum is written in Chinese and presents the skill content as fixed in that language, with no indication that users may choose another language or that the skill is intentionally limited to a Chinese-language context. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

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/batch_roster.py (reported line 142)May include surrounding context.

python
if not args.no_name and s["name"]:
            cmd += ["--name", s["name"]]

        r = subprocess.run(cmd, capture_output=True, text=True)
        if r.returncode != 0:
            print(f"  ✗ #{i} {s['name'] or '(unnamed)'} 生成失败: {r.stderr.strip()}")
            summary["students"].append({"index": i, "name": s["name"], "status": "failed", "error": r.stderr.strip()})

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The module description and most instructional content are centered on Chinese-language use, including a Chinese-titled course system and Chinese defaults. While English strings exist later, the file presents Chinese as the baseline behavior and does not indicate that users can choose their language or that the skill is region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The generator functions use lang="zh" as the default, which enforces a specific language unless the caller explicitly overrides it. Under the stated policy, forcing a language without user opt-in is a natural-language locale violation unless the restriction is documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The function signature sets lang="zh" as the default, which makes the skill produce Chinese-language content unless the caller explicitly overrides it. This is a natural-language policy concern because it forces a specific language by default rather than offering a user choice or requiring opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The function signature sets lang="zh" by default and immediately uses that locale via T = I18N[lang], which means the skill will produce Chinese-language content unless the caller explicitly overrides it. This is a natural-language policy concern because it forces a specific language by default rather than offering or requesting user choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The function signature sets lang="zh" by default and immediately uses that locale via I18N[lang]. This forces a specific language unless the caller explicitly overrides it, which is a natural-language policy concern when no user choice or opt-in is described in the file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The natural-language docstring presents the tool description, usage, and output conventions entirely in Chinese, and the script's user-facing strings are also Chinese-only. This indicates a fixed language choice without offering the user a language or locale option, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring presents all usage and release-gating instructions only in Chinese, including statements that it is ready for publication and must be run before release. Under the stated policy, forcing a specific language without user opt-in is a natural-language locale violation.

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/test_skill.py (reported line 30)May include surrounding context.

python
# ---------- helpers ---------------------------------------------------------

def run(args, cwd=None):
    return subprocess.run(
        [PYTHON, str(GENERATOR)] + list(args),
        capture_output=True, text=True, cwd=cwd,
    )

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/test_skill.py (reported line 37)May include surrounding context.

python
def run_batch(args):
    return subprocess.run(
        [PYTHON, str(BATCH)] + list(args),
        capture_output=True, text=True,
    )

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This markdown file is natural-language content, and all visible headings and descriptions are presented only in Chinese. The file does not indicate that Chinese is a user-selected option or that the skill is intentionally limited to a Chinese-speaking locale, which can conflict with language/locale choice expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The file presents Chinese as the default interaction/output mode and only later lists --lang en as an optional flag for an English interface. This can be read as forcing a specific language by default without explicitly offering the user a language choice at the start of the workflow.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

SQP-3 applies to all file types and covers language or locale policy violations in natural-language content. The feature line claims a Chinese-English bilingual interface, but the visible worksheet preview and usage text are predominantly Chinese and do not indicate any user-selectable language or opt-in, which may imply a default language constraint.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/test_skill.py:147