Back to skill

Security audit

License Plate Reader

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed TrafficEye license-plate OCR helper that uploads a user-selected image to a configurable API endpoint, with no hidden persistence or unrelated file access.

Install only if you are comfortable sending selected vehicle images and plate data to TrafficEye or another endpoint you configure. Keep TRAFFICEYE_API_URL on a trusted HTTPS host, avoid query-string API key transport unless required, and use a scoped TrafficEye API key.

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
recognize_plate.py:270
Finding

Configurable Untrusted Endpoint Can Receive Sensitive Images and API Credentials

Content
View full analysis
str: """Append the API key to the query string when query-mode auth is enabled.""" if api_key_mode != "query" or not api_key: return api_url parsed = urllib.parse.urlsplit(api_url) query_items = urllib.parse.parse_qsl(parsed.query, keep_blank_values=True) query_items.append((api_key_name, api_key)) updated_query = urllib.parse.urlencode(query_items) return urllib.parse.urlunsplit((parsed.scheme, parsed.netloc, parsed.path, updated_query, parsed.fragment)) def call_api( image_path: Path, api_url: str, api_key: str | None, api_key_mode: str, api_key_name: str, request_json: str | None, file_field: str, request_field: str, timeout_s: float, ) -> Any: """Upload the image to the API and parse the JSON response.""" fields: dict[str, str | bytes] = {} if request_json: fields[request_field] = request_json if api_key_mode == "form" and api_key: fields[api_key_name] = api_key image_bytes = image_path.read_bytes() body, content_type = build_multipart_body( fields, {file_field: (image_path.name, image_bytes, None)}, ) request_url = build_request_url(api_url, api_key, api_key_mode, api_key_name) headers = {"Content-Type": content_type, "Content-Length": str(len(body))} if api_key_mode == "header" and api_key: headers[api_key_name] = api_key elif api_key_mode == "bearer" and api_key: headers["Authorization"] = f"Bearer {api_key}" request = urllib.request.Request(request_url, data=body, headers=headers, method="POST") try: with urlli ...[truncated 3568 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (5)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill performs sensitive actions—reading local files, consuming environment-provided secrets, and sending data over the network—but does not declare an explicit tool scope or permissions boundary. That increases the chance an agent or reviewer will invoke it without clear visibility into its capabilities, especially since it uploads user-supplied local images to an external API.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill description explains that it accepts a local image path and uploads the image to the TrafficEye API, but it does not prominently warn users that their local file contents are sent to a third-party service for processing. This creates a privacy and data-handling risk because users may provide sensitive images without informed consent, particularly in an agent workflow that resolves attachments to local files automatically.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code uploads a local image file to a third-party remote API, which can expose sensitive personal data without an explicit user-facing disclosure at execution time. Because license plates and surrounding image content may contain regulated or privacy-sensitive information, silent transmission increases privacy and compliance risk, especially if the operator assumes processing is local.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest frames the skill as taking a local image and using the TrafficEye API for ANPR/ALPR, but the code additionally sources API URL, API key, auth mode, and related settings from environment variables. Reading local environment configuration is not described in the skill purpose and introduces a capability beyond straightforward image processing plus API invocation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code accepts only "text" or "json" for --format, and the preceding condition returns successfully for either value. The final raised error says the API response lacked readable OCR text, but that condition is unrelated to format handling and will never be triggered, so the inline intent expressed by the error message does not match actual behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.