Back to skill

Security audit

Litigation Docs Generator

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent for Chinese litigation document generation, but it should be reviewed because it processes confidential legal material and can create Excel files from unsanitized inputs.

Review before installing in legal or client-facing workflows. Use only trusted or redacted uploads, manually review any custom template before it replaces the bundled template, verify all generated legal citations with a lawyer, and harden the Excel generator by validating numeric fields and neutralizing formula-prefixed text before sharing generated workbooks.

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/generate_interest_calc.py:267
Finding

Spreadsheet Formula Injection Through Untrusted Workbook Inputs

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_interest_calc.py, lines 267, 373, 407, and 433
Vulnerability Type: XLSX formula injection and insufficient input validation
Risk Level: Medium

Vulnerable Code

python
# Line 267: attacker-controlled title written directly to a cell
c = ws.cell(row=row, column=1, value=title)
python
# Lines 373-375: principal is interpolated into an Excel formula
ef = f"={principal}*D{row}*C{row}/360"
ec = ws.cell(row=row, column=5)
ec.value = ef
python
# Line 407: attacker-controlled submitter written directly to a cell
ws.cell(row=row, column=5, value=submitter).font = data_font
python
# Lines 431-434: --items JSON bypasses argparse's numeric type validation
items = []
if args.items:
    items = json.loads(args.items)
elif args.principal and args.start and args.end:

Technical Analysis

The generator places the command-line title and submitter values directly into XLSX cells without neutralizing formula-prefixed input. In openpyxl, a string beginning with = can be stored as an Excel formula rather than inert text.

The principal field presents an additional injection path. When supplied through --principal, argparse enforces type=float. However, entries supplied through --items are only parsed with json.loads() and are not validated against a schema. An attacker can therefore provide a string instead of a number. That string is interpolated directly into the formula:

python
ef = f"={principal}*D{row}*C{row}/360"

This permits attacker-controlled Excel formula syntax to be inserted into the generated workbook. There is also no validation that rates are finite numbers, dates form a valid ordered interval, or item objects contain values of the expected types.

The generated workbook is intended for delivery as a legal document, making it plausible that another person will open it in Excel, LibreOffice, or similar software. Depending on the spr ...[truncated 2082 chars]

Remediation
View remediation

Remediation Suggestions

  1. Enforce a schema for every --items entry.

    • Require principal and rate to be numeric values.
    • Reject booleans, strings, arrays, and objects in numeric fields.
    • Require start and end to be valid ISO dates.
    • Require the start date to be no later than the end date.
    • Reject unknown keys where practical.
  2. Require finite, bounded numeric values.

python
import math

def validate_number(value, field, minimum=None, maximum=None):
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        raise ValueError(f"{field} must be numeric")
    value = float(value)
    if not math.isfinite(value):
        raise ValueError(f"{field} must be finite")
    if minimum is not None and value < minimum:
        raise ValueError(f"{field} is below the permitted minimum")
    if maximum is not None and value > maximum:
        raise ValueError(f"{field} exceeds the permitted maximum")
    return value

Apply this validation to each item's principal and optional rate before calling generate_excel().

  1. Neutralize formula-prefixed text before writing it to a cell.
python
def safe_excel_text(value):
    text = str(value)
    if text.startswith(("=", "+", "-", "@")):
        return "'" + text
    return text

Use this function for title, submitter, and any other user-controlled text written to the workbook:

python
c = ws.cell(row=row, column=1, value=safe_excel_text(title))
ws.cell(
    row=row,
    column=5,
    value=safe_excel_text(submitter),
).font = data_font
  1. Construct formulas only from validated numeric values.
python
principal = validate_number(
    item["principal"],
    "principal",
    minimum=0.01,
)
ef = f"={principal:.2f}*D{row}*C{row}/360"

An even safer design is to place the validated principal in a dedicated numeric cell and make formulas reference that cell instead of interpolating input into formula source text.

  1. **Add regre ...[truncated 684 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

声明描述的是一个综合性的诉讼文书生成技能,重点在于按模板批量生成8份法律文书并结合外部法律检索。实际代码只实现了其中一个非常具体的子功能:生成利息损失计算表 Excel,且通过内置利率数据和 openpyxl 直接构建工作簿完成,没有模板加载、没有法律检索、没有其他文书生成,也没有企业信息补全。因此代码行为只覆盖声明中的很小一部分,且主目的明显更窄、更单一,属于实质性描述不符。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

声明描述的是一个面向民商事诉讼文书的完整业务技能,核心能力包括法律检索、模板驱动批量生成8种材料、企业信息自动补全和特定法律文书流程控制。但提供的代码只是底层文档渲染组件:输入一个模板文件和变量 JSON,替换占位符后保存为一个 .docx。它既没有外部法律数据库访问代码,也没有 references/ 目录约束、批处理多个模板、生成 Excel、或任何诉讼业务规则。虽然“模板驱动生成文书”这一点与声明有部分相关,但范围和主功能明显缩减,无法支撑所宣称的完整技能,因此属于描述与实际行为不匹配。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill describes behaviors that require reading local templates and scripts (references/*, scripts/*) but does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authorization ambiguity: a host may grant broader-than-necessary file access or reviewers may be unable to verify whether file reads are intentionally constrained to safe paths.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill actively encourages users to upload signed retainer agreements and other legal documents, which commonly contain sensitive personal, financial, and case information, without a clear privacy, minimization, or retention warning. In the legal context this is more dangerous because the documents may include confidential client data, IDs, addresses, fee terms, and privileged matter details.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation allows user-uploaded contract content to replace bundled templates, undermining the claim that generation is strictly constrained by trusted references/ templates. In a prompt-driven agent, converting untrusted uploaded content into active templates can introduce prompt/template injection, cause unexpected instructions to be followed, or produce manipulated legal documents.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The instructions direct the agent to read and extract key information from uploaded contracts without disclosing the sensitivity of the processing or warning users about confidential legal information. This creates a privacy risk and can lead users to disclose more than necessary, especially in a workflow involving lawyer-client engagement materials.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Transforming uploaded contracts into YAML templates and substituting them for bundled references turns untrusted input into executable control data for document generation. Because YAML frontmatter defines formatting and structure, this expands user influence over the generation pipeline and weakens the intended trust boundary around fixed templates.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The document content is entirely written in Chinese and specifies Chinese fonts such as 宋体 and 仿宋, which indicates a fixed language/locale requirement. There is no natural-language indication that this template is optional, user-selected, or restricted to a China-specific legal workflow, so it appears to impose a locale without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This file contains natural-language descriptions and CLI help text that assume Chinese as the only interaction language. Under the policy, forcing a specific language without user opt-in is a locale/language constraint that should be either optional or explicitly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The command-line interface presents all help text in Chinese and does not provide any language selection or note that the tool is intentionally restricted to Chinese-speaking users. This is a natural-language policy issue because it imposes a specific language by default.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The template hard-codes Chinese fonts such as 宋体 and 仿宋 and uses a Chinese date format like "{year}年 月 日", which imposes a specific locale. Because the file does not indicate that the template is optional, user-selectable, or restricted to a clearly documented region-specific context, this is a natural-language locale policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The template content and formatting are entirely fixed to Chinese language conventions, including Chinese text, Chinese date formatting, and Chinese fonts, with no indication that users may choose another language or locale. Under the policy criteria, a skill that forces a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file specifies Chinese fonts (宋体, 仿宋) and the entire interview record template is written in Chinese, with no indication that language selection is optional or limited to a China-specific use case. Under the policy rule, forcing a specific language or locale without user opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The file is entirely written and formatted for Chinese usage, including Chinese fonts, Chinese date format, and Chinese legal text, but it does not state that it is intended only for Chinese-language or China-specific legal use. This can violate language/locale policy when a skill or template implicitly forces a specific locale without giving the user a choice or documenting the constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The file specifies Chinese fonts such as 宋体 and 仿宋 and presents the document entirely in Chinese, which can amount to a language/locale constraint. There is no natural-language note explaining that the template is intended specifically for Chinese legal filings or offering a language/locale choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains user-facing natural-language text entirely in Chinese in the module docstring and usage instructions, which effectively forces a specific language/locale without user opt-in. The same pattern appears throughout the script's visible prompts and messages, indicating a language policy issue rather than an implementation detail.

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

python
def get_rate(rec: RateRecord, term: str) -> float:
    idx = _RATE_TERM_MAP.get(term, 1)
    return getattr(rec, _RATE_ATTRS[idx])


def auto_select_term(start: date, end: date) -> str:

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

python
ws.cell(row=r, column=1).alignment = center
        ws.cell(row=r, column=1).number_format = 'yyyy-mm-dd'
        for ci, attr in enumerate(_RATE_ATTRS, 2):
            c = ws.cell(row=r, column=ci, value=getattr(rec, attr))
            c.font = data_font; c.alignment = center; c.number_format = '0.00'
            c.border = thin
        ws.cell(row=r, column=1).border = thin

Static analysis

No suspicious patterns detected.