Back to skill

Security audit

zhuangshi-suanliang

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a legitimate local construction estimating tool, but it has review-worthy risks when processing untrusted CAD-derived data and running an external validator script.

Install only if you are comfortable running local Python scripts on project/CAD-derived files. Treat imported CAD metadata as untrusted, inspect generated spreadsheets before sharing or opening with external content enabled, and prefer running with a trusted cad-file-reader installation or disabling validation when the validator path is not controlled.

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/decor_qty.py:990
Finding

Untrusted CAD-Derived Text Is Written as an Active Spreadsheet Formula

Content
View full analysis

Vulnerability Details

File Location: scripts/cad_measure_to_input.py:92-108, 272-275; scripts/decor_qty.py:619-639, 990-996
Vulnerability Type: Spreadsheet formula injection
Risk Level: Medium

Technical Analysis

Text originating from CAD measurement JSON is inserted into output records without neutralizing spreadsheet formula prefixes. For example, the measurement formula and review_reason fields are incorporated into the 说明 column:

python
if value is None:
    detail = (
        f"未换算:图面值 {fmt(row.get('value_drawing_units'))} {row.get('drawing_unit') or ''};"
        f"{row.get('review_reason') or '缺比例或单位'}"
    )
else:
    detail = f"{row.get('formula') or ''};{row.get('review_reason') or ''}".strip(";")
output = blank()
output.update({
    "楼层": floor,
    "区域": zone,
    "房间": room_name(row),
    "部位类型": "待确认-面积" if kind == "area" else "待确认-长度",
    "做法名称": "CAD识图测量候选(需绑定做法)",
    "做法类型": "通用",
    "间数": "1",
    "说明": f"{detail};final_quantity=false",
    "依据": f"cad-file-reader:{row.get('source_schema') or ''}:{row.get('source_id') or ''}",
    "需核对": "是",
})

These values are written directly to CSV:

python
target.parent.mkdir(parents=True, exist_ok=True)
with target.open("w", encoding="utf-8-sig", newline="") as handle:
    writer = csv.DictWriter(handle, fieldnames=HEADERS)
    writer.writeheader()
    writer.writerows(rows)

When this generated CSV is subsequently processed by decor_qty.py, externally derived fields such as 说明, 依据, room names, and node information remain strings in the calculation result:

python
result: dict[str, Any] = {
    "行号": int(source_line) if source_line is not None else row_index + 2,
    "楼层": _text(row.get("楼层")),
    "区域": _text(row.get("区域")),
    "房间": _text(row.get("房间")),
    "房间类型": _text(row.get("房间类型")),
    "部位类型": part,
    "做法编号": code,
    "做法名称": _text(row.get("做法名
...[truncated 3144 chars]
Remediation
View remediation

Remediation Suggestions

  1. Introduce one centralized sanitizer for all text written to CSV or XLSX:

    python
    def spreadsheet_safe(value: Any) -> Any:
        if not isinstance(value, str):
            return value
        if value.startswith(("=", "+", "-", "@")):
            return "'" + value
        return value
    
  2. Apply the sanitizer to every externally derived text value before calling csv.DictWriter.writerows() or Worksheet.append().

  3. For XLSX output, explicitly store untrusted values as literal strings rather than formulas. Do not rely solely on visual formatting or cell number formats.

  4. Preserve numeric values as numeric types and sanitize only text fields, so quantity calculations and report formatting remain functional.

  5. Apply protection at the final output boundary even if earlier import stages also sanitize data. This prevents project-rule files, manually edited CSV files, or future import paths from bypassing the protection.

  6. Add regression tests covering values beginning with =, +, -, and @ in CAD formula, review-reason, room, source-ID, node, description, and basis fields. Verify that generated XLSX cells are stored as literal strings and have a non-formula data type.

  7. Document that imported CAD metadata is treated as untrusted data and must never be interpreted as spreadsheet syntax.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (19)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/decor_qty.py \

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
scripts/decor_qty.py \

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/cad_measure_to_input.py (reported line 251)May include surrounding context.

python
parser.add_argument("--zone", default="CAD识图候选", help="区域名称")
    parser.add_argument("--descriptive", default=None,
                        help="可选:cad-descriptive-geometry 中间数据 JSON(房间/墙段/吊顶/洞口/做法索引)")
    parser.add_argument("--validate", "--no-validate", dest="validate", action=argparse.BooleanOptionalAction,
                        default=True, help="导入前用 cad-file-reader 校验交接 JSON(缺底座时静默跳过)")
    args = parser.parse_args()

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · templates/快速概算输入表.csv (reported line 1)May include surrounding context.

text
楼层,区域,房间,部位类型,做法编号,做法名称,做法类型,节点编号,节点详图,长_m,宽_m,高_m,周长_m,门窗洞口面积_m2,洞口侧壁增加_m2,扣减长度_m,直接面积_m2,直接长度_m,防水上翻高度_m,附加层面积_m2,附加层长度_m,附加层宽度_m,搭接宽度_mm,卷材幅宽_mm,涂膜厚度_mm,防水道数,间数,说明,依据,需核对
二层,A区,办公室,地面/楼面,D01,地砖楼面,通用,,,,,,,,,,13.5,,,,,,,,,,1,矩形房间,建施-05 房间装修表,
二层,A区,走廊,踢脚,T01,地砖踢脚,通用,,,,,,22.0,,,2.0,,,,,,,,,,,1,门洞扣减,建施-05,
二层,A区,办公室,墙面,W01,乳胶漆墙面,通用,,,,,3.1,17.2,1.8,0.6,,,,,,,,,,,,1,层高按剖面图,建施-05/结施-08,

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · templates/装饰算量输入表.csv (reported line 1)May include surrounding context.

text
楼层,区域,房间,部位类型,做法编号,做法名称,做法类型,节点编号,节点详图,长_m,宽_m,高_m,周长_m,门窗洞口面积_m2,洞口侧壁增加_m2,扣减长度_m,直接面积_m2,直接长度_m,防水上翻高度_m,附加层面积_m2,附加层长度_m,附加层宽度_m,搭接宽度_mm,卷材幅宽_mm,涂膜厚度_mm,防水道数,间数,说明,依据,需核对
二层,A区,办公室,地面/楼面,D01,地砖楼面,通用,,,,,,,,,,13.5,,,,,,,,,,1,矩形房间,建施-05 房间装修表,
二层,A区,走廊,踢脚,T01,地砖踢脚,通用,,,,,,22.0,,,2.0,,,,,,,,,,,1,门洞扣减,建施-05,
二层,A区,办公室,墙面,W01,乳胶漆墙面,通用,,,,,3.1,17.2,1.8,0.6,,,,,,,,,,,,1,层高按剖面图,建施-05/结施-08,

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill documents execution of local scripts and reliance on file access, shell commands, and possibly environment data, but it does not declare any explicit tool scope such as allowed-tools or permissions. That creates an authorization gap: an agent runtime may grant broader capabilities than users expect, increasing the risk of unintended file access, command execution, or misuse of ambient credentials when processing untrusted project files.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code file contains natural-language instructions and user-facing descriptions entirely in Chinese, including the module docstring and operational notes. Under the policy, forcing a specific language without user opt-in is a locale-policy violation unless the constraint is explicitly justified, which is not stated here.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
92% confidence
Finding

The script executes an external shell script located via the CAD_SKILL_DIR environment variable or user-writable home-directory skill paths. Although subprocess.run is invoked with a list (reducing shell-injection risk), this still allows arbitrary code execution if an attacker can influence the validator path or place a malicious cad_validate.sh in one of the searched directories.

Content

Scanner excerpt · scripts/cad_measure_to_input.py (reported line 63)May include surrounding context.

python
if not validator.exists():
        return None
    try:
        r = subprocess.run(
            [str(validator), str(input_path)],
            capture_output=True, text=True, timeout=120,
        )

Tainted flow: 'validator' from os.environ.get (line 59, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
97% confidence
Finding

There is a tainted flow from CAD_SKILL_DIR into the executable path passed to subprocess.run, enabling execution of attacker-controlled code when the environment is manipulated. In agent or automation contexts, environment variables are often easier to influence than source code, making this a realistic code-execution vector.

Content

Scanner excerpt · scripts/cad_measure_to_input.py (reported line 63)May include surrounding context.

python
if not validator.exists():
        return None
    try:
        r = subprocess.run(
            [str(validator), str(input_path)],
            capture_output=True, text=True, timeout=120,
        )

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_cad_measure_to_input.py (reported line 31)May include surrounding context.

python
src = root / "measure.json"
            out = root / "decor.csv"
            src.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
            proc = subprocess.run([sys.executable, str(SCRIPT), "--measurements", str(src), "--out", str(out), "--floor", "二层"], capture_output=True, text=True)
            self.assertEqual(proc.returncode, 0, proc.stderr)
            with out.open(encoding="utf-8-sig") as handle:
                rows = list(csv.DictReader(handle))

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_cad_measure_to_input.py (reported line 60)May include surrounding context.

python
out = root / "decor.csv"
            src.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
            desc.write_text(json.dumps(descriptive, ensure_ascii=False), encoding="utf-8")
            proc = subprocess.run([sys.executable, str(SCRIPT), "--measurements", str(src),
                                   "--descriptive", str(desc), "--out", str(out), "--floor", "二层"],
                                  capture_output=True, text=True)
            self.assertEqual(proc.returncode, 0, proc.stderr)

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_cad_measure_to_input.py (reported line 83)May include surrounding context.

python
out = root / "decor.csv"
            src.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")
            env = {"PATH": "/usr/bin:/bin", "CAD_SKILL_DIR": str(root / "not-exists")}
            proc = subprocess.run([sys.executable, str(SCRIPT), "--measurements", str(src),
                                   "--out", str(out), "--floor", "二层"],
                                  capture_output=True, text=True, env=env)
            self.assertEqual(proc.returncode, 0, proc.stderr)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The file is entirely written in Chinese, including headings and release notes, with no indication that language selection is optional or that the skill is intentionally limited to a Chinese-speaking audience. Under the policy rule for natural-language constraints, this can be treated as a locale/language restriction that is not explicitly justified in the file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This JSON file uses Chinese field names and Chinese natural-language guidance throughout, with no indication that language choice is optional or configurable. Under the stated policy, a skill that effectively requires a specific language without user opt-in can be considered a locale/language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This JSON manifest-like file uses Chinese-only field names and room/template labels throughout, with no indication that the skill is region-specific or that users can opt into this locale. Under the policy, a fixed language/locale without user choice or documented justification is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The file’s natural-language content is entirely in Chinese and provides no indication that users may choose another language or locale. Under the policy rule for language/locale, this can be interpreted as a forced locale because the skill content is presented only in one language without opt-in or documented region-specific justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

该 JSON 文件的字段名与说明文本均固定为中文,如“口径”“清单规则”“知识库来源”等,未见任何允许用户选择语言或说明其仅适用于特定中文区域/流程的自然语言声明。按规则,强制单一语言且无用户选择可能构成自然语言层面的 locale 政策问题。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This JSON file uses Chinese-only natural-language fields and values throughout, such as policy text, labels, and rules, with no indication that users may select another language. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale restriction is explicitly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The JSON keys and descriptive text are entirely in Chinese, which implies a fixed language/locale for the skill data. Under the policy, language constraints should either be optional for the user or explicitly justified as region-specific; that justification is not present in this file.

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/tests/test_decor_qty.py:11