T09 · Insecure Skill Coding Practices
Note
- Location
- handler.py:333
- Finding
- Unvalidated Handler Input Causes Invocation Failure## 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
- ## 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.
