Back to skill

Security audit

园林算量

Security checks for vulnerabilities and agentic risk

Overview

ClawScan marks this skill suspicious with medium confidence, mainly because the scanners report a substantial mismatch between its stated landscaping quantity purpose and additional code-checking functionality, plus a confirmed flaw in a contract integrity check.

Treat this as a review warning, not a finding of malicious intent. Before installing, consider whether the reported purpose mismatch is acceptable for your use, and review the skill’s code and dependency version yourself. The scan reports full component coverage, but Skillspector also returned an exit status error with serialization warnings, so the overall medium confidence should be kept in mind.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (19)

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

所提供代码的主要功能是源代码跨平台 lint,而非苗木统计或铺装面积计算;其中没有园林数据处理、数量统计或面积计算逻辑。虽然 lint 可以作为软件维护的辅助工具,但此代码所实现的独立功能与声明的园林算量用途没有体现出直接联系,因此存在实质性用途不匹配。修复命令仅被打印,并未执行;可见代码未显示网络访问或文件修改行为。

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/self_test.py (reported line 59)May include surrounding context.

python
def run(cmd: list[str], cwd: Path) -> tuple[int, str]:
    import os as _os
    env = dict(_os.environ)
    env["PYTHONIOENCODING"] = "ascii"
    env["PYTHONUTF8"] = "1"
    r = subprocess.run(cmd, cwd=str(cwd), env=env, capture_output=True, text=True)

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
80% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/yuanlin_qty.py (reported line 676)May include surrounding context.

python
token = str(token).strip()
            if not token:
                continue
            if token.lower() in low or token in name:
                cand = (len(token), -gi, label, token)
                if best is None or cand > best:
                    best = cand

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
80% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/yuanlin_qty.py (reported line 692)May include surrounding context.

python
("wildflower", "地被"), ("meadow", "地被"), ("bulb", "地被"), ("aquatic", "地被"),
                ("climber", "其他"), ("vine", "其他"), ("pot", "其他"), ("ornamental", "其他"))
    for token, label in fallback:
        if token in low or token in name:
            return label, token
    u = (unit or "").strip().lower().replace(" ", "")
    if u in ("m2", "㎡", "m²", "平方米") or "株/m2" in u or "株/㎡" in u or "株/m²" in u:

Skill declares no tool scope ('permissions' or 'allowed-tools') but code capabilities were detected: env, file_read, file_write, shell.

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Formal admission does not enforce the documented hash-consistency requirement.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

Even with require_hash=True, an absent embedded hash produces only a warning, allowing a contract with self-declared reader/bus provenance and a nonempty ID to receive formal eligibility. Removing the hash can therefore bypass the integrity check and allow altered quantity inputs to appear formally admitted; the non-settlement scope limits, but does not eliminate, downstream planning impact.

Content

No source excerpt is available for this finding.

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · scripts/contract_support.py (reported line 62)May include surrounding context.

python
os.environ.get("CAD_SKILL_DIR"),
        Path.home() / ".codex" / "skills" / "cad-file-reader",
        Path.home() / ".claude" / "skills" / "cad-file-reader",
        *sorted(Path.home().glob(".workbuddy/skills/*/cad-file-reader")),
    ])

File System Enumeration

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Code scans file system directories looking for sensitive files. This could be reconnaissance for credential theft.

Content

Scanner excerpt · scripts/entry_gate.py (reported line 113)May include surrounding context.

python
out.append(Path(raw).expanduser())
    out.extend(root / slug for root in _default_roots())
    if slug == "cad-file-reader":
        out.extend(sorted(Path.home().glob(".workbuddy/skills/*/cad-file-reader")))
    return out

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/lint_cross_platform.py (reported line 67)May include surrounding context.

python
"SIGKILL 仅 POSIX。fix: 平台分支外避免直接 kill;Windows 用 terminate()"),
    ("NATIVE_DYLIB",
     re.compile(r"\b[\w.-]+\.dylib\b"),
     "dylib 是 macOS 原生库格式。fix: 仓库内 sudo 二进制请走 platform 分支;Windows/Linux 由 pip wheel 提供"),
    ("DARWIN_SO",
     re.compile(r"\.cpython-\d+[^-]*-darwin\.so\b"),
     "darwin 专有扩展名出现在业务脚本里通常是误引用。fix: vendor 由各平台 setup/pip 重建,不应在脚本里硬依赖"),

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/pyboot.py (reported line 85)May include surrounding context.

python
manifest = root / "manifest.json"
    if manifest.is_file():
        try:
            data = __import__("json").loads(manifest.read_text(encoding="utf-8"))
            version = data.get("version")
            if isinstance(version, str) and version.strip():
                return version.strip()

The preflight script claims to run self-tests but only prints the self-test heading.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The preflight announces a full self-test stage but executes no tests before continuing toward a completion message. This creates a release-assurance gap in which regressions, including broken contract safeguards, can pass the advertised preflight unchecked.

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

python
env = dict(_os.environ)
    env["PYTHONIOENCODING"] = "ascii"
    env["PYTHONUTF8"] = "1"
    r = subprocess.run(cmd, cwd=str(cwd), env=env, capture_output=True, text=True)
    return r.returncode, (r.stdout or "") + (r.stderr or "")

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/tests/test_yuanlin_qty.py (reported line 43)May include surrounding context.

python
cmd += ["--plant-library", str(lib)]
    if args.get("no_default_plant_library"):
        cmd.append("--no-default-plant-library")
    r = subprocess.run(cmd, capture_output=True, text=True)
    assert r.returncode == 0, r.stderr
    payload = json.loads(r.stdout.strip().splitlines()[-1])
    return payload

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/tests/test_yuanlin_qty.py (reported line 55)May include surrounding context.

python
for key in ("scan", "landscape", "rules", "dxf_block_paving", "dxf_block_refs", "evidence_dir"):
        if args.get(key):
            cmd += [f"--{key.replace('_', '-')}", str(args[key])]
    r = subprocess.run(cmd, capture_output=True, text=True)
    text = (r.stdout + r.stderr).strip()
    assert r.returncode == want, f"exit={r.returncode}(期望 {want}): {text}"
    assert "不直接识图" in text, text

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

python
if dxf_refs:
        cmd += ["--block-refs", str(dxf_refs)]
    try:
        proc = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
    except Exception as exc:
        sys.stderr.write(f"[yuanlin] cad_landscape_geometry 调用失败:{exc}\n")
        raise SystemExit(1) from None

Manual-input reports can mark quantities as final despite the documented guarantee that final_quantity is forced to false.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

Manual-input mode is recorded in the guard, but plant and paving rows determine final_quantity and mainline inclusion without consulting that guard. These rows, summaries, and the Markdown report are written before any possible downstream provenance enforcement, so manually supplied quantities can appear final despite the explicit guarantee, potentially misleading procurement or quantity-review workflows.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The open-ended dependency range allows installations to receive unreviewed future openpyxl releases, reducing reproducibility and exposing installations to dependency regressions or compromised releases. This is a supply-chain hardening weakness, not evidence that the currently installed dependency is malicious.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
# 依赖声明:优先走识图底座 cad-file-reader 的 vendor/;缺失时:
#   python3 -m pip install -r requirements.txt
openpyxl>=3.1

Unverifiable Dependency: openpyxl has 2 known advisory(ies) (CVE-2017-5992 (Improper Restriction of XML External Entity Reference in Openpyxl); CVE-2017-5992 (Openpyxl 2.4.1 resolves external entities by default, which allows remote attack)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

OSV returned advisories for this package, but its resolved version is unknown. A package-name lookup does not establish whether the installed release is affected by those advisories.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/pyboot.py (reported line 44)May include surrounding context.

python
os.environ.setdefault("PYTHONIOENCODING", "utf-8")
    os.environ.setdefault("PYTHONUTF8", "1")
    for _name in ("stdout", "stderr"):
        _stream = getattr(sys, _name, None)
        _reconf = getattr(_stream, "reconfigure", None)
        if callable(_reconf):
            try: