Back to skill

Security audit

Contract Risk Helper

Security checks for vulnerabilities and agentic risk

Overview

This skill is a local contract-risk checker whose behavior matches its stated purpose and shows no evidence of hidden data access, network use, persistence, or destructive actions.

Use this for preliminary contract risk spotting only. It appears to process text locally without uploading or storing it, but users should still avoid treating its output as legal advice and should be aware that general contract-review prompts may invoke it.

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

Note
Location
handler.py:333
Finding

Unvalidated Handler Input Causes Invocation Failure

Content
View full analysis

Vulnerability Details

File Location: handler.py:333-334
Vulnerability Type: Improper input type validation
Risk Level: Low

Vulnerable Code

python
contract_text = skill_input.get("contract_text", "")
if not contract_text or not contract_text.strip():

Technical Analysis

The public handle() entry point assumes that skill_input is a dictionary and that its contract_text member is a string. It invokes .get() and .strip() before validating either type.

Although the lower-level scan() function checks whether its input is a string, execution does not reach that validation when contract_text is a truthy non-string value. Similarly, passing a non-dictionary as skill_input fails at the .get() call.

No input schema or equivalent type enforcement is declared in skill.json. Consequently, malformed or adversarial input can raise an uncaught AttributeError and terminate the invocation.

Attack Path

  1. An attacker or malformed integration invokes the Skill with a non-string value, such as {"contract_text": 1}.
  2. handle() retrieves the integer through skill_input.get().
  3. Because the integer is truthy, evaluation proceeds to contract_text.strip().
  4. The integer has no .strip() method, causing an uncaught AttributeError.
  5. The current Skill invocation fails instead of returning a structured validation error.

A similar failure occurs if the top-level input is not a dictionary, because .get() is called without first validating skill_input.

Impact Assessment

Exploitation can cause application-level denial of service for the affected invocation and may produce repeated failures if an upstream caller retries malformed requests. The flaw does not grant additional privileges and provides no demonstrated path to command execution, data disclosure, network access, persistence, or cross-session compromise. Its scope is limited to availability and error handli ...[truncated 83 chars]

Remediation
View remediation

Remediation Suggestions

Validate both the top-level input and the contract text before invoking type-specific methods:

python
def handle(skill_input: dict) -> dict:
    if not isinstance(skill_input, dict):
        return {
            "ok": False,
            "error": "Invalid input: an object is required."
        }

    contract_text = skill_input.get("contract_text", "")
    if not isinstance(contract_text, str):
        return {
            "ok": False,
            "error": "Invalid contract text: a string is required."
        }

    if not contract_text.strip():
        return {
            "ok": False,
            "error": "No contract text was provided."
        }

    results = scan(contract_text)
    output = format_results(results)
    # Continue constructing the successful response.

Also apply a documented maximum input length to limit excessive CPU and memory consumption, declare an input schema if supported by the Skill platform, and add tests for non-dictionary input, None, integers, lists, nested objects, and oversized strings.

Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger list includes broad, everyday phrases such as '帮我看合同' and '合同检查', which can cause the skill to activate on general contract-related requests rather than explicit invocation. Over-broad activation is dangerous because it can hijack unrelated conversations, produce unsolicited legal-style guidance, and increase the chance that sensitive contract text is routed into this skill unexpectedly.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The handler docstring declares a language field, but the implementation never reads it and unconditionally formats results in both Chinese and English. This imposes a specific locale/output style regardless of user preference, which matches the policy concern about forcing language behavior without opt-in.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The docstring at L271 describes the function as a straightforward scan for risk patterns, but the code later skips matches whose suggestion fields are empty. In particular, the confidentiality return/destroy pattern is matched yet deliberately omitted, so the implementation does not fully reflect the apparent scanning behavior described in the documentation.

Content

No source excerpt is available for this finding.