Back to skill

Security audit

Personal Id Ocr

Security checks for vulnerabilities and agentic risk

Overview

This is a real SCNet OCR wrapper, but it can upload sensitive identity documents or other local files to a configurable external endpoint with limited privacy disclosure and weak scoping.

Review before installing. Use it only if you are comfortable sending ID-card or document images to SCNet's cloud OCR service. Keep SCNET_API_BASE pointed at the intended SCNet HTTPS endpoint, do not pass unrelated sensitive files, and rotate the API key if the config file or endpoint may have been altered.

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/main.py:77
Finding
Unrestricted API Endpoint Can Disclose Identity Documents and API Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.py:77`, `scripts/main.py:85-111` **Vulnerability Type**: Unvalidated configurable network destination **Risk Level**: High ### Vulnerable Code ```python config.setdefault('SCNET_API_BASE', 'https://api.scnet.cn/api/llm/v1') ``` ```python api_base = config['SCNET_API_BASE'] api_key = config['SCNET_API_KEY'] url = f"{api_base}/ocr/recognize" headers = { 'Authorization': f'Bearer {api_key}' } try: with open(file_path, 'rb') as f: files = { 'file': (os.path.basename(file_path), f, mime_type) } data = { 'ocrType': ocr_type, 'channelTag': "scnetSkills" } response = requests.post( url, headers=headers, data=data, files=files, timeout=60 ) except Exception as e: sys.exit(f"Network request failed: {str(e)}") ``` ### Technical Analysis The OCR operation legitimately requires sending the selected document to the SCNet cloud service. However, `SCNET_API_BASE` is read from configuration and used verbatim to construct the request URL. The implementation does not parse or validate the configured URL before attaching the bearer credential and uploading the complete document. In particular, it does not enforce: - The HTTPS scheme. - The documented `api.scnet.cn` hostname. - An approved port or path prefix. - The absence of embedded URL credentials. - A destination allowlist. - A policy for redirects. Because `requests.post` follows redirects by default, destination handling also depends on implicit library behavior rather than an explicit policy suitable for identity-document uploads. The Skill only needs access to the documented SCNet API for its declared function. Permitting transmission to arbitrary destinations exceeds that minimum network privilege. ### Attack Path 1. An attacker, compromised automation component, or misleading setup instr ...[truncated 1191 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove support for a configurable API destination unless custom deployments are a documented requirement. 2. If configurability is required, parse the URL with a standard URL parser and enforce: - Scheme exactly equal to `https`. - Hostname exactly equal to an approved hostname such as `api.scnet.cn`. - Approved destination ports only. - An expected path prefix. - No embedded username or password. 3. Use an explicit hostname allowlist rather than suffix matching, which can accept deceptive domains. 4. Set `allow_redirects=False` for sensitive uploads. If redirects are operationally required, validate every redirect target before resending credentials or document content. 5. Require explicit user confirmation before using any non-default enterprise endpoint. 6. Keep the API credential scoped to the minimum required service operations and support rapid rotation. 7. Add tests that reject HTTP URLs, deceptive subdomains, embedded credentials, unexpected ports, malformed URLs, and unapproved redirect targets. 8. Clearly disclose the destination, data categories, retention policy, and third-party processing implications before uploading identity documents. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:89
Finding
Missing Input Validation Allows Arbitrary Local Files to Be Uploaded<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.py:89-111`, `scripts/main.py:181-189` **Vulnerability Type**: Unrestricted local file upload and missing OCR operation validation **Risk Level**: Medium ### Vulnerable Code ```python if not os.path.isfile(file_path): sys.exit(f"Error: file does not exist - {file_path}") mime_type, _ = mimetypes.guess_type(file_path) if mime_type is None: mime_type = 'application/octet-stream' headers = { 'Authorization': f'Bearer {api_key}' } try: with open(file_path, 'rb') as f: files = { 'file': (os.path.basename(file_path), f, mime_type) } data = { 'ocrType': ocr_type, 'channelTag': "scnetSkills" } response = requests.post( url, headers=headers, data=data, files=files, timeout=60 ) except Exception as e: sys.exit(f"Network request failed: {str(e)}") ``` ```python def main(): if len(sys.argv) != 3: print("Usage: python main.py <ocrType> <filePath>") print("Available ocrType value: ID_CARD") sys.exit(1) ocr_type = sys.argv[1] file_path = sys.argv[2] config = load_config() recognize_with_retry(ocr_type, file_path, config) ``` ### Technical Analysis The documentation declares `ID_CARD` as the supported OCR type and describes document-oriented inputs. The implementation only verifies that the supplied path is a regular file. It does not enforce the documented OCR type, allowed file extensions, content signatures, file-size limits, or approved source directories. When MIME inference fails, the file is still uploaded as `application/octet-stream`. Therefore, the network operation is not limited to identity-document images or PDFs and can function as a generic local-file uploader. The script does not autonomously enumerate files, bypass operating-system permissions, or select sensitive paths. Exploi ...[truncated 1296 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce the declared operation with an exact check such as `ocr_type == "ID_CARD"`. 2. Allowlist only the file formats genuinely required by the OCR service. 3. Validate file content using trusted signature detection rather than relying solely on filename extensions or `mimetypes.guess_type`. 4. Reject unknown files instead of uploading them as `application/octet-stream`. 5. Resolve paths to canonical absolute paths and, where practical, restrict access to user-selected or explicitly approved directories. 6. Require explicit user confirmation showing the resolved path and destination before uploading files containing identity information. 7. Apply conservative file-size and page-count limits before initiating the network request. 8. Do not support compressed archives unless required. If archives are supported, validate archive structure, decompressed size, and entry types. 9. Add tests confirming rejection of unsupported OCR types, executable files, configuration files, unknown binary files, oversized files, and paths outside approved locations. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (21)

Missing User Warnings

High
Confidence
97% confidence
Finding
This skill handles highly sensitive personal identity documents, yet the documentation does not clearly and prominently warn that local image files and extracted identity data are sent to a third-party OCR service. That creates a significant privacy and compliance risk because users may unknowingly transmit PII such as ID numbers, names, birth dates, and addresses off-device.

Credential Access

High
Category
Privilege Escalation
Content
# 获取技能根目录(脚本所在目录的上一级)
SKILL_ROOT = Path(__file__).parent.parent.absolute()
ENV_FILE = SKILL_ROOT / "config" / ".env"
# --- 新增:重试配置 ---
MAX_RETRIES = 3            # 最大重试次数
RETRY_BACKOFF_FACTOR = 2   # 退避因子,每次重试等待时间翻倍
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# --------------------

def load_config():
    """从 .env 文件加载配置,若文件不存在则抛出友好错误"""
    if not ENV_FILE.exists():
        error_msg = (
            "\n===============================================\n"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# --------------------

def load_config():
    """从 .env 文件加载配置,若文件不存在则抛出友好错误"""
    if not ENV_FILE.exists():
        error_msg = (
            "\n===============================================\n"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# --------------------

def load_config():
    """从 .env 文件加载配置,若文件不存在则抛出友好错误"""
    if not ENV_FILE.exists():
        error_msg = (
            "\n===============================================\n"
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
* [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/)
* [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
* [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
* [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
* [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill declares capabilities that imply local file access, network access, and shell execution, but it does not define an explicit tool scope such as permissions or allowed-tools. In an agent setting, that ambiguity can enable broader-than-expected execution and data access, especially because the skill processes local files and sends content to a remote API.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The metadata presents this as a personal ID OCR skill, but the body advertises broader OCR use cases such as bank cards, invoices, and generic text extraction. That mismatch can cause users or orchestrators to invoke the skill on more sensitive or unintended documents than expected, expanding data exposure and undermining consent boundaries.

External Transmission

Medium
Category
Data Exfiltration
Content
SCNET_API_KEY=your_scnet_api_key_here

# API 基础地址(一般无需修改)
SCNET_API_BASE=https://api.scnet.cn/api/llm/v1
```
2. 添加:`SCNET_API_KEY=你的密钥`
3. 设置文件权限为 600(仅所有者可读写)
Confidence
91% confidence
Finding
The documentation identifies a remote API endpoint, confirming that local document content will be transmitted externally for processing. In the context of ID-card OCR, this is security-relevant because the transmitted data is highly sensitive personal information, and external transfer materially increases privacy, compliance, and breach exposure.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The usage examples encourage invoice and generic text OCR even though the declared input limits ocrType to ID_CARD. This inconsistency can lead to unintended execution on unrelated local files and transmission of data the user did not expect this skill to handle.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The trigger guidance is broad enough to match general OCR requests, not just personal ID recognition. In an agent environment, overly broad invocation criteria can cause accidental activation on arbitrary files, increasing the chance of sensitive document exfiltration to the external OCR provider.

External Transmission

Medium
Category
Data Exfiltration
Content
| 变量名 | 默认值 | 说明 |
|--------|--------|------|
| SCNET_API_KEY | 必需 | Scnet API 密钥 |
| SCNET_API_BASE | https://api.scnet.cn/api/llm/v1 | API 基础地址(一般无需修改) |

### 输出
Confidence
91% confidence
Finding
The configuration section again specifies the remote API base, reinforcing that this skill depends on sending data to an external service. Because the skill processes identity documents, this external transmission is a meaningful security concern unless clearly disclosed and tightly scoped.

External Transmission

Medium
Category
Data Exfiltration
Content
# Sugon-Scnet OCR API 文档摘要

## 接口地址
`POST https://api.scnet.cn/api/llm/v1/ocr/recognize`

## 请求头
- `Content-Type: multipart/form-data`
Confidence
90% confidence
Finding
The skill sends uploaded identity-document images and extracted OCR content to an external third-party API endpoint, which constitutes external transmission of highly sensitive personal data. In this skill context, the data includes government ID images and fields such as name, address, birth date, and ID number, making any unintended sharing, retention, or compromise significantly more dangerous than a generic external API call.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The module docstring presents the skill name, inputs, and outputs only in Chinese, and the command-line help and runtime messages throughout the file are likewise Chinese-only. This creates a language policy concern because the skill effectively enforces a specific language without any opt-in or alternative locale support.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
"   b) 配置文件:\n"
            f"      mkdir -p {SKILL_ROOT}/config\n"
            f"      echo 'SCNET_API_KEY=你的密钥' > {ENV_FILE}\n"
            f"      chmod 600 {ENV_FILE}\n"
            "\n配置完成后重新运行。"
        )
        sys.exit(error_msg)
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
"   b) 配置文件:\n"
            f"      mkdir -p {SKILL_ROOT}/config\n"
            f"      echo 'SCNET_API_KEY=你的密钥' > {ENV_FILE}\n"
            f"      chmod 600 {ENV_FILE}\n"
            "\n配置完成后重新运行。"
        )
        sys.exit(error_msg)
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

External Transmission

Medium
Category
Data Exfiltration
Content
)
        sys.exit(error_msg)

    config.setdefault('SCNET_API_BASE', 'https://api.scnet.cn/api/llm/v1')
    return config

def recognize_with_retry(ocr_type, file_path, config, retry_count=0):
Confidence
95% confidence
Finding
This skill sends uploaded identity-document images and extracted PII to an external third-party OCR API at api.scnet.cn. Because the skill processes highly sensitive national ID data, external transmission materially increases privacy, compliance, and data-handling risk, especially if users are not explicitly informed and the endpoint/operator is not tightly controlled.

Natural-Language Policy Violations

Medium
Confidence
82% confidence
Finding
The natural-language description is written only in Chinese and is narrowly scoped to Chinese national ID cards, but the manifest does not explicitly document this locale constraint as a region-specific limitation or offer language choice. This can violate language/locale policy expectations when users are not informed of or opting into the locale-specific behavior.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
The natural-language instructions and examples are presented only in Chinese, which effectively imposes a specific language on users. The file does not indicate that this is region-specific or provide an alternative language option.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
该文档全文仅以中文呈现,未说明这是面向特定中文用户群体或区域场景的受限文档,也未提供其他语言选项。根据语言/地区策略,若技能或说明材料隐含强制特定语言而无用户选择或合理限定,可构成自然语言层面的策略问题。

Vague Triggers

Low
Confidence
78% confidence
Finding
This manifest describes the skill's OCR capability but does not state when the skill should or should not be invoked, nor provide any trigger phrases or exclusion conditions. For manifest files, missing specificity around invocation scope can lead to overly broad matching by orchestrators or assistants.

Static analysis

No suspicious patterns detected.