T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/package_version_tracker.py:130
- Finding
- Untrusted Registry Metadata Is Rendered Without Sanitization<![CDATA[ ## Vulnerability Details **File Location**: `scripts/package_version_tracker.py`, lines 16-27, 61-75, and 130-143 **Vulnerability Type**: Unsanitized rendering of attacker-controlled remote content **Risk Level**: Medium ### Vulnerable Code ```python with urllib.request.urlopen(url, timeout=10) as response: data = json.loads(response.read().decode()) return { "success": True, "name": data.get("name"), "version": data.get("version"), "description": data.get("description", ""), "license": data.get("license", ""), "homepage": data.get("homepage", ""), "repository": data.get("repository", {}).get("url", ""), } ``` ```python with urllib.request.urlopen(url, timeout=10) as response: data = json.loads(response.read().decode()) info = data.get("info", {}) return { "success": True, "name": info.get("name"), "version": info.get("version"), "summary": info.get("summary", ""), "author": info.get("author", ""), "license": info.get("license", ""), "home_page": info.get("home_page", ""), "pypi_url": info.get("package_url", ""), } ``` ```python lines = [] lines.append(f"📦 **{package_type.upper()} Package: {data.get('name', 'N/A')}**") lines.append(f"") lines.append(f"**Version:** `{data.get('version', 'N/A')}`") if package_type == "npm": if data.get("description"): lines.append(f"**Description:** {data.get('description')}") if data.get("license"): lines.append(f"**License:** {data.get('license')}") else: # pypi if data.get("summary"): lines.append(f"**Summary:** {data.get('summary')}") if data.get("author"): lines.append(f"**Author:** {data.get('author')}") ``` ### Technical Analysis The skill retrieves package metadata from public npm and PyPI registry APIs. Fields including the package name, version, description, license, summary, and author are controlled by pac ...[truncated 2703 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Treat all registry response fields as untrusted external data. 2. Remove ANSI escape sequences and disallowed C0/C1 control characters before rendering values. 3. Escape Markdown metacharacters when generating Markdown output, or emit a structured format such as JSON when the output will be consumed programmatically. 4. Place remote text in clearly delimited quoted or code blocks and label it as registry-supplied metadata. 5. Apply reasonable length limits to fields such as descriptions, summaries, authors, package names, and licenses. 6. Keep data and instructions separated in downstream AI workflows. Tool responses should explicitly state that registry metadata must never be followed as instructions. 7. Consider a centralized sanitization function, for example: ```python import re ANSI_ESCAPE = re.compile(r"\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") CONTROL_CHARS = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]") def sanitize_registry_text(value: object, max_length: int = 2000) -> str: text = "" if value is None else str(value) text = ANSI_ESCAPE.sub("", text) text = CONTROL_CHARS.sub("", text) return text[:max_length] ``` 8. Apply the sanitizer immediately after parsing the registry response and perform context-specific Markdown escaping at the final rendering sink. ]]>
