Back to skill

Security audit

Json Schema Toolkit

Security checks for vulnerabilities and agentic risk

Overview

The skill is a local JSON-schema utility, but its code generation and validation behavior can produce unsafe or misleading results from untrusted schemas.

Review before installing if you may process untrusted schemas or rely on this for security-sensitive validation. Do not import, execute, compile, or ship generated Python or TypeScript from untrusted schema names or property names without sanitizing them first, and do not treat its validator as a full JSON Schema implementation.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/json_schema.py:180
Finding
Unsanitized schema names and property names allow generated-code injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/json_schema.py:180-187`, `scripts/json_schema.py:207-209`, and `scripts/json_schema.py:239-249` **Vulnerability Type**: Generated source-code injection **Risk Level**: High ### Vulnerable Code ```python def schema_to_typescript(schema, name="Root", indent=0): """Convert JSON Schema to TypeScript interface.""" pad = " " * indent lines = [] schema_type = schema.get("type", "any") if schema_type == "object": lines.append(f"{pad}interface {name} {{") props = schema.get("properties", {}) required = set(schema.get("required", [])) for key, prop in props.items(): opt = "" if key in required else "?" ts_type = _ts_type(prop) lines.append(f"{pad} {key}{opt}: {ts_type};") ``` ```python parts = [] required = set(schema.get("required", [])) for k, v in props.items(): opt = "" if k in required else "?" parts.append(f"{k}{opt}: {_ts_type(v)}") return "{ " + "; ".join(parts) + " }" ``` ```python if schema.get("type") == "object": lines.append("@dataclass") lines.append(f"class {name}:") props = schema.get("properties", {}) required = set(schema.get("required", [])) if not props: lines.append(" pass") for key, prop in props.items(): py_t = _py_type(prop) if key not in required: lines.append(f" {key}: Optional[{py_t}] = None") else: lines.append(f" {key}: {py_t}") ``` ### Technical Analysis The converter directly interpolates the CLI-controlled `--name` argument and schema-controlled property names into generated Python and TypeScript source code. It does not validate that these values are legal identifiers, escape special characters, safely quote property names, or account for reserved words. An attacker can therefore construc ...[truncated 1715 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate `--name` against a strict target-language identifier policy before generation. 2. Reject names containing whitespace, line breaks, punctuation, declaration delimiters, or other characters outside the permitted identifier syntax. 3. Maintain target-specific reserved-word lists and reject or deterministically rename reserved identifiers. 4. For TypeScript properties, emit safely escaped string-literal keys, such as JSON-encoded property names, when a key is not a valid unquoted identifier. 5. For Python dataclasses, do not interpolate arbitrary JSON property names as field identifiers. Generate safe field names and preserve the original JSON key through explicit serialization metadata or a key-mapping table. 6. Prefer rejection with a clear error over silently producing invalid or unsafe source. 7. Add tests using malicious names and keys containing newlines, quotes, braces, semicolons, comments, decorators, and reserved words. 8. Parse or compile generated artifacts during testing to verify that user-controlled text cannot create additional declarations or executable statements. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/json_schema.py:57
Finding
Incomplete JSON Schema handling permits validation bypasses<![CDATA[ ## Vulnerability Details **File Location**: `scripts/json_schema.py:57-62`, `scripts/json_schema.py:93-117`, and `scripts/json_schema.py:156-164` **Vulnerability Type**: Fail-open schema validation and type confusion **Risk Level**: Medium ### Vulnerable Code The generator emits `oneOf` for heterogeneous arrays: ```python item_schemas = [infer_type(item) for item in value] # If all items have the same type, use that types_seen = set() for s in item_schemas: types_seen.add(json.dumps(s, sort_keys=True)) if len(types_seen) == 1: return {"type": "array", "items": item_schemas[0]} else: return {"type": "array", "items": {"oneOf": item_schemas}} ``` The validator silently skips schemas containing `$ref`, and its Python type mapping treats booleans as integers because `bool` is a subclass of `int`: ```python def _validate(schema, data, path, errors): """Recursive schema validation (covers common JSON Schema keywords).""" if not schema or not isinstance(schema, dict): return # Handle $ref (not supported in basic mode) if "$ref" in schema: return # Skip refs in basic validation # Type check schema_type = schema.get("type") if schema_type: type_map = { "string": str, "integer": int, "number": (int, float), "boolean": bool, "array": list, "object": dict, "null": type(None), } if schema_type in type_map: expected = type_map[schema_type] if not isinstance(data, expected): ``` Array items are passed to `_validate`, but `_validate` has no implementation for `oneOf`: ```python # Array validation if isinstance(data, list): items_schema = schema.get("items", {}) if "minItems" in schema and len(data) < schema["minItems"]: errors.append(f"{path}: array length {len(data)} ...[truncated 2642 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject booleans explicitly when validating `integer` or `number`: - For `integer`, require `isinstance(data, int) and not isinstance(data, bool)`. - For `number`, require `isinstance(data, (int, float)) and not isinstance(data, bool)`. 2. Implement standards-compliant `$ref` resolution, including local JSON Pointer references and cycle protection. If reference resolution is unavailable, return a validation error instead of silently accepting the value. 3. Implement `oneOf` by validating against every branch and requiring exactly one successful branch. 4. Add actual validation for every advertised `format`, preferably using strict parsers rather than permissive regular expressions. 5. Fail closed when an unsupported validation keyword is encountered, or expose an explicit compatibility mode that reports unsupported keywords prominently. 6. Ensure schemas generated by the tool use only constructs that its validator can enforce. 7. Clearly document the supported JSON Schema dialect and subset rather than implying general Draft 2020-12 compliance. 8. Add regression tests covering booleans against integer and number schemas, unresolved references, nested references, zero/multiple matching `oneOf` branches, heterogeneous generated arrays, and invalid formatted strings. 9. For security-sensitive use, consider using a mature JSON Schema implementation with full Draft 2020-12 support. ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (1)

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Static analysis

No suspicious patterns detected.