Back to skill

Security audit

ID Card Recognition OCR - 身份证识别

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims, but it handles government ID images through a third-party OCR service and has an overbroad file-read path that could send unintended local files.

Review before installing. Use this only when you are comfortable sending ID-card, passport, license, or similar document images to JisuAPI. Do not run it on workspaces containing untrusted symlinks or unrelated sensitive files, use a dedicated low-privilege API key, avoid retaining uploaded document images locally, and redact returned PII when possible.

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
idcardrecognition.py:25
Finding
Workspace Symlink Bypass Enables Unauthorized File Exfiltration<![CDATA[ ## Vulnerability Details **File Location**: `idcardrecognition.py`, lines 25–45 and 68–100 **Vulnerability Type**: Insufficient canonical-path validation and symlink traversal **Risk Level**: High ### Vulnerable Code ```python def _normalize_local_path(user_path: str, field: str) -> Dict[str, Any]: """ 规范化并限制本地文件路径,只允许在当前工作目录及其子目录内读写。 禁止绝对路径和目录穿越(包含 ..),避免被恶意提示利用读取任意系统文件。 """ if not user_path: return { "error": "invalid_param", "message": f"field '{field}' is empty", } if os.path.isabs(user_path): return { "error": "invalid_path", "message": f"Absolute path is not allowed for '{field}'", } norm = os.path.normpath(user_path) if norm.startswith("..") or norm == "..": return { "error": "invalid_path", "message": f"Path traversal is not allowed for '{field}'", } base = os.getcwd() full = os.path.join(base, norm) return {"error": None, "path": full, "relative": norm} ``` ```python path = safe["path"] if not os.path.isfile(path): return {"pic": None, "error": f"File not found: {safe['relative']}"} try: with open(path, "rb") as f: raw = f.read() except Exception as e: return {"pic": None, "error": f"Failed to read file: {e}"} try: encoded = base64.b64encode(raw).decode("utf-8") except Exception as e: return {"pic": None, "error": f"Failed to base64-encode file: {e}"} return {"pic": encoded, "error": None} ``` ```python params = {"appkey": appkey} data = {"pic": pic_base64, "typeid": typeid} try: resp = requests.post(IDCARD_RECOG_URL, params=params, data=data, timeout=20) except Exception as e: return {"error": "request_failed", "message": str(e)} ``` ### Technical Analysis The path validation rejects absolute paths and lexical parent-direct ...[truncated 2667 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve both the allowed root and candidate path with `os.path.realpath()` or `pathlib.Path.resolve(strict=True)`. 2. Verify canonical containment with `os.path.commonpath()` rather than string-prefix comparisons: ```python root = os.path.realpath(os.getcwd()) candidate = os.path.realpath(os.path.join(root, norm)) if os.path.commonpath([root, candidate]) != root: raise ValueError("Resolved path is outside the allowed directory") ``` 3. Reject symbolic links explicitly with `os.path.islink()` where links are unnecessary. 4. On supported platforms, open files using `os.open()` with `O_NOFOLLOW`, then read from the returned descriptor. Validate the descriptor with `os.fstat()` to reduce time-of-check-to-time-of-use exposure. 5. Apply a maximum input size before reading the entire file into memory. 6. Validate the image signature and supported image format before sending content externally. File extensions alone are insufficient. 7. Run the Skill under a dedicated account with access only to the intended workspace and no access to unrelated secrets. 8. Require explicit user authorization before transmitting identity documents or other sensitive images to the third-party service. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
idcardrecognition.py:91
Finding
API Credential Exposed Through URL Query Parameter<![CDATA[ ## Vulnerability Details **File Location**: `idcardrecognition.py`, lines 91–100 **Vulnerability Type**: Sensitive credential exposure in request URL **Risk Level**: Medium ### Vulnerable Code ```python def _call_idcard_api(appkey: str, pic_base64: str, typeid: int) -> Dict[str, Any]: """ 调用身份证识别接口。 typeid: 证件类型,参考 /idcardrecognition/type 接口。 """ params = {"appkey": appkey} data = {"pic": pic_base64, "typeid": typeid} try: resp = requests.post(IDCARD_RECOG_URL, params=params, data=data, timeout=20) except Exception as e: return {"error": "request_failed", "message": str(e)} ``` ### Technical Analysis Passing `appkey` through the `params` argument causes `requests` to place the credential in the URL query string. HTTPS protects the URL while it is in transit between properly validated TLS endpoints, but it does not prevent the complete URL from being recorded by the client environment, debugging facilities, forward or reverse proxies, API gateways, monitoring products, or server access logs. Query strings are commonly retained longer and exposed to more operational personnel and systems than authorization headers. If any such log is disclosed or accessed without authorization, the API key can be recovered and reused. The network request itself is required for the declared cloud OCR functionality. The concern is the credential transport mechanism, not the disclosed transmission of the document to the configured provider. ### Attack Path 1. A legitimate user invokes the OCR Skill. 2. The request is constructed with `appkey` in the query string. 3. A proxy, gateway, monitoring component, debug trace, or JisuAPI access log records the full request URL. 4. An attacker or unauthorized operator obtains access to that recorded URL. 5. The attacker extracts the API key and submits requests under the victim's account until the key is revoked or otherwi ...[truncated 618 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. If supported by JisuAPI, send the credential in an authorization header rather than the URL: ```python headers = {"Authorization": f"Bearer {appkey}"} resp = requests.post( IDCARD_RECOG_URL, headers=headers, data={"pic": pic_base64, "typeid": typeid}, timeout=20, ) ``` 2. If the provider requires `appkey` as a query parameter, document that constraint and configure all clients, proxies, gateways, and monitoring systems to redact the parameter. 3. Ensure exception handling and diagnostics never emit the prepared request URL with an unredacted query string. 4. Use a dedicated API key with only the permissions and quota necessary for this Skill. 5. Rotate the key periodically and immediately after suspected log exposure. 6. Restrict access to URL and API gateway logs, minimize retention, and monitor the key for unusual usage or unexpected quota consumption. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill requires an API key in the environment and instructs use of a remote OCR API, but it does not declare any explicit tool scope or permissions for network and secret access. This weakens user/operator awareness and policy enforcement around external data transfer, especially problematic because the data involved includes highly sensitive identity documents.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The description does not prominently warn that uploaded ID images and extracted personal information will be transmitted to JisuAPI, a third party. Because this skill processes government ID documents and returns highly sensitive PII, lack of upfront disclosure can lead to users unknowingly exposing identity data to an external service.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The recommended workflow tells operators to save ID document images locally without warning about secure handling, temporary storage, deletion, or access control. Local persistence of passports, ID cards, and similar images increases the risk of accidental retention, unauthorized access, backup leakage, or forensic recovery.

External Transmission

Medium
Category
Data Exfiltration
Content
import requests


IDCARD_RECOG_URL = "https://api.jisuapi.com/idcardrecognition/recognize"


def _normalize_local_path(user_path: str, field: str) -> Dict[str, Any]:
Confidence
90% confidence
Finding
The hardcoded external OCR endpoint indicates the skill is designed to transmit document contents off-host to a third-party service. In the context of ID-card recognition, that external transmission materially increases sensitivity because the payload contains identity-document images and extracted personal data, making privacy exposure and regulatory risk significant if users are not clearly informed and protected.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill sends highly sensitive ID-card image data to a third-party OCR service, but the code and described skill behavior provide no explicit user-facing consent, disclosure, or warning at the point of use. Because identity documents contain PII and often enough data for identity fraud, silent transmission to an external processor creates a real privacy and compliance risk even though the transport uses HTTPS.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
Natural-language strings in the file describe the skill and usage details in Chinese, including the external API reference and several function/docstring descriptions, without indicating that the skill is intentionally locale-specific or offering a language choice. This can create a language-policy issue if users are expected to understand the skill behavior but are forced into a specific language implicitly.

Static analysis

No suspicious patterns detected.