Back to skill

Security audit

birth_medical_cert_ocr

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate OCR purpose, but it uploads highly sensitive birth-certificate documents and API credentials through a configurable network destination that is broader than the declared endpoint.

Review before installing. Only use this with birth medical certificate files you are authorized to process, because images leave the local machine for Scnet OCR. Do not customize SCNET_API_BASE unless you fully trust and verify the endpoint, and prefer environment/secret-store API key handling over a plaintext .env file.

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:82
Finding
Configurable API Base URL Enables Credential and Sensitive Document Exfiltration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.py:82`, `scripts/main.py:111-138` **Vulnerability Type**: Unrestricted network destination for sensitive data **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 ) ``` ### Technical Analysis The script reads `SCNET_API_BASE` from the local configuration and uses it directly to construct the upload destination. It performs no validation of: - The URL scheme - The destination hostname - The destination port - The expected API path - Whether transport encryption is required Consequently, the configured value can point to an arbitrary host, including a plaintext HTTP endpoint. The request includes both the bearer API credential and the complete user-selected birth-certificate file. This behavior conflicts with the network permission declared in `skill.yaml`, which lists only: ```text https://api.scnet.cn/api/llm/v1/ocr/recognize ``` Birth certificates can contain newborn information, parental identity numbers, addresses, medical details, and certificate identifiers. Sending this material to an unrestricted destination exceeds the minimum network privilege represented by the manifest. ### Attack Path 1. An attacker gains the ability to alter `config/.env`, or persuades the user to apply an unsafe configuration. 2. The attacker sets `SCNET_API_BASE` to an attacke ...[truncated 1245 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `SCNET_API_BASE` configurability if the Skill is intended to communicate only with the documented Scnet service. 2. Use a fixed endpoint: ```python OCR_ENDPOINT = "https://api.scnet.cn/api/llm/v1/ocr/recognize" ``` 3. If endpoint customization is operationally necessary: - Parse the URL with `urllib.parse.urlparse`. - Require the `https` scheme. - Enforce an explicit hostname allowlist. - Enforce the expected API path. - Reject embedded credentials, fragments, and unexpected ports. 4. Disable redirects with `allow_redirects=False`, or independently validate every redirect destination before following it. 5. Never send the bearer credential to a destination that has not passed validation. 6. Align `skill.yaml`, `SKILL.md`, and runtime behavior so the declared network permission exactly matches all permitted destinations. 7. Add automated tests proving that HTTP URLs, unapproved domains, malformed URLs, and unexpected ports or paths are rejected. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:115
Finding
Insufficient File Validation Allows Upload of Arbitrary Readable Local Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/main.py:115-138` **Vulnerability Type**: Unrestricted local file upload and insufficient input validation **Risk Level**: Medium ### Vulnerable Code ```python if not os.path.isfile(file_path): sys.stderr.write(f"错误: 文件不存在 - {file_path}\n") sys.exit(1) 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 ) ``` ### Technical Analysis The script verifies only that the supplied path refers to an existing regular file. It does not verify that the file is actually a birth-certificate image or another explicitly supported OCR format. `mimetypes.guess_type()` infers the media type from the filename extension rather than inspecting the file contents. If no type can be inferred, the script explicitly permits the upload by assigning `application/octet-stream`. The implementation lacks: - An extension allowlist - File signature or magic-byte validation - A maximum file-size limit - Validation that the path is the file explicitly approved by the user - Rejection of symbolic links resolving to unintended files - Confirmation immediately before transmitting sensitive content Although `ocrType` is restricted to `BIRTH_CERTIFICATE`, that restriction controls only a form field. It does not constrain the actual contents of the uploaded file. ### Attack Path 1. An attacker influences the command arguments used to invoke the Skill, or causes an agent to select an unintended local path. 2. The attacker ...[truncated 1110 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define an explicit allowlist of supported formats based on the actual API contract. 2. Validate both the filename extension and the file's binary signature; do not rely solely on `mimetypes.guess_type()`. 3. Reject unknown content instead of defaulting to `application/octet-stream`. 4. Apply a strict maximum file-size limit before opening or uploading the file. 5. Resolve the path with `Path.resolve()` and verify that it corresponds to the file explicitly selected or approved by the user. 6. Decide whether symbolic links are necessary. If not, reject them before opening the file. 7. Request explicit confirmation immediately before uploading a document containing highly sensitive personal or medical data. 8. Where supported by the host framework, use a file-selection capability rather than accepting unrestricted path strings. 9. Add tests covering disguised extensions, unknown binary files, symbolic links, oversized inputs, and paths outside the approved selection. ]]>
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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (20)

Credential Access

High
Category
Privilege Escalation
Content
permissions:
  read_local_files:
    paths:
      - "${SKILL_ROOT}/config/.env"
      - "${USER_PROVIDED_FILE_PATH}"
    reason: 读取用户提供的出生医学证明图片文件及本地配置文件。
  network:
Confidence
87% confidence
Finding
The skill requests permission to read its local config/.env file containing the API key. Although this is likely needed for normal operation, granting file-read access to credentials increases the blast radius if the script is compromised, modified, or reused in unintended ways; the skill also processes sensitive PII, so credential misuse could enable unauthorized API usage or abuse under the user's account.

Credential Access

High
Category
Privilege Escalation
Content
# 获取技能根目录(脚本所在目录的上一级)
SKILL_ROOT = Path(__file__).parent.parent.absolute()
ENV_FILE = SKILL_ROOT / "config" / ".env"

# --- 新增:重试配置 ---
MAX_RETRIES = 3            # 最大重试次数
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.

Credential Access

High
Category
Privilege Escalation
Content
permissions:
  read_local_files:
    paths:
      - "${SKILL_ROOT}/config/.env"
      - "${USER_PROVIDED_FILE_PATH}"
    reason: 读取用户提供的出生医学证明图片文件及本地配置文件。
  network:
Confidence
91% confidence
Finding
The skill requests read access to ${SKILL_ROOT}/config/.env, which commonly stores secrets such as API keys. Granting a skill file-read access to a local .env is broader than necessary for normal credential injection and creates a path for secret exposure, especially when the same skill also has network egress to an external service. In this context, access to highly sensitive user documents plus local secrets materially increases blast radius.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The substantive skill instructions, warnings, prerequisites, and usage guidance are presented entirely in Chinese in the main operational section of the README. This creates a natural-language locale constraint without user opt-in or an explicit justification that the skill is intended only for Chinese-speaking or region-specific users.

External Transmission

Medium
Category
Data Exfiltration
Content
```ini
SCNET_API_KEY=your_scnet_api_key_here
SCNET_API_BASE=https://api.scnet.cn/api/llm/v1
```

3. 运行识别:
Confidence
93% confidence
Finding
The README explicitly instructs users to send birth certificate images containing extremely sensitive personal and medical data to a third-party API endpoint. Even though the data flow is disclosed, external transmission of highly sensitive documents materially increases privacy, compliance, and exposure risk if the service, transport, retention policy, or API key handling is weak or misconfigured.

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.

External Transmission

Medium
Category
Data Exfiltration
Content
reason: 读取用户提供的出生医学证明图片文件及本地配置文件。
  network:
    endpoints:
      - "https://api.scnet.cn/api/llm/v1/ocr/recognize"
    reason: 将出生医学证明图片上传至 Scnet OCR 服务进行识别处理。
  execute_script:
    command: "python3 ${SKILL_ROOT}/scripts/main.py BIRTH_CERTIFICATE <filePath>"
Confidence
96% confidence
Finding
The skill explicitly uploads user-provided birth medical certificate images to a third-party OCR endpoint. These documents contain highly sensitive personal and medical data for infants and parents, so external transmission creates real confidentiality and compliance risk if consent, minimization, retention, or vendor controls are inadequate. The skill context makes this more dangerous because the data class is unusually sensitive and identity-related.

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
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

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
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

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
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

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
Confidence
92% confidence
Finding
The skill is hardwired to transmit documents to an external service endpoint, creating an external data egress path. In the context of birth-certificate OCR, this is especially sensitive because the uploaded files likely contain protected personal and medical information, so any unintended or insufficiently disclosed transmission materially increases privacy exposure.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script sends the user-supplied file to a third-party OCR API, which means potentially sensitive personal data from birth certificates is transmitted off-host. In this skill context, the document contains highly sensitive PII, and the script does not present an explicit runtime consent notice or data-handling warning before upload, increasing privacy and compliance risk.

External Transmission

Medium
Category
Data Exfiltration
Content
reason: 读取用户提供的出生医学证明图片文件及本地配置文件。
  network:
    endpoints:
      - "https://api.scnet.cn/api/llm/v1/ocr/recognize"
    reason: 将出生医学证明图片上传至 Scnet OCR 服务进行识别处理。
  execute_script:
    command: "python3 ${SKILL_ROOT}/scripts/main.py <ocrType> <filePath>"
Confidence
93% confidence
Finding
The skill explicitly transmits a user-provided birth medical certificate image to an external OCR API. This document contains highly sensitive personal data about a newborn and parents, so external transmission creates real privacy, compliance, and data-handling risk even if it is the intended function. The narrow document-specific purpose lowers suspicion of maliciousness, but the sensitivity of the data makes the exposure significant.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
This markdown file presents core skill documentation content in Chinese only, including the title and feature descriptions. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale constraint is explicitly documented and justified.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
All user-facing messages, usage text, and instructions in the file are written only in Chinese, and the script does not provide any mechanism for users to select another language. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless clearly justified as region-specific.

Static analysis

No suspicious patterns detected.