Back to skill

Security audit

Bank Card Ocr

Security checks for vulnerabilities and agentic risk

Overview

This bank-card OCR skill is mostly purpose-aligned, but it uploads highly sensitive card images to a remote service and allows the upload destination to be changed without validation.

Review before installing. Use this only if you trust Scnet with bank-card images and the related personal/financial data. Keep SCNET_API_BASE at the documented https://api.scnet.cn/api/llm/v1 value unless you intentionally control another endpoint, use test or redacted cards where possible, protect and rotate the API key, and run it in an isolated environment with only the needed files accessible.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.py:76
Finding
Configurable API endpoint can disclose bank-card images and API credentials## Vulnerability Details **File Location**: `scripts/main.py:76-110` **Vulnerability Type**: Unrestricted sensitive-data transmission endpoint **Risk Level**: High ### Vulnerable Code ```python 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): """ 带重试机制的 OCR 识别函数。 当遇到 429 (Too Many Requests) 时,自动等待后重试。 调用 Scnet OCR API 进行识别""" api_base = config['SCNET_API_BASE'] api_key = config['SCNET_API_KEY'] url = f"{api_base}/ocr/recognize" # 检查文件是否存在 if not os.path.isfile(file_path): sys.exit(f"错误: 文件不存在 - {file_path}") # 自动检测 MIME 类型 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 Skill must transmit a bank-card image to a remote OCR service to perform its declared function, and this transmission is disclosed in `SKILL.md`. However, the destination is taken directly from the configurable `SCNET_API_BASE` value without validating its scheme or hostname. The resulting request contains two sensitive assets: - The Scnet API credential in the `Authorization` header. - The complete user-selected file in a multipart upload. If the configuration contains an attacker-controlled URL, the script sends those assets to that server. It also permits a plaintext `http://` base URL, which could expose the request ...[truncated 1331 chars]
Remediation
## Remediation Suggestions 1. Remove endpoint configurability if custom deployments are not required, and use the documented constant: ```python API_URL = "https://api.scnet.cn/api/llm/v1/ocr/recognize" ``` 2. If configurability is required, parse the URL with `urllib.parse.urlparse` and enforce: - Scheme exactly equal to `https`. - Hostname exactly equal to `api.scnet.cn`, or an explicit administrator-maintained allowlist. - An expected port and path prefix. - No embedded username or password. 3. Reject malformed URLs, plaintext HTTP endpoints, IP literals, loopback addresses, and unapproved internal or external hosts. 4. Disable redirects with `allow_redirects=False` unless they are required by the documented API. If redirects are required, validate every redirect destination before resending sensitive content. 5. Display the validated destination and obtain explicit user consent before uploading a bank-card image. 6. Use a narrowly scoped API token and support token revocation and rotation in case configuration tampering is detected.

T08 · Insecure Dependencies

Note
Location
SKILL.md:68
Finding
Unpinned third-party dependency installation reduces supply-chain integrity## Vulnerability Details **File Location**: `SKILL.md:68` **Vulnerability Type**: Unpinned runtime dependency **Risk Level**: Low ### Vulnerable Code ```bash pip install requests ``` ### Technical Analysis The installation instructions retrieve the latest available version of `requests` without pinning a reviewed version or verifying package hashes. Consequently, identical installations performed at different times may resolve to different package versions. The package name is legitimate and there is no evidence that this project intentionally installs a malicious dependency. Nevertheless, the installation method lacks reproducibility and integrity controls. A compromised package release, package-index account, index configuration, or dependency release could introduce malicious code during installation or execution. ### Attack Path 1. A user follows the documented `pip install requests` instruction. 2. `pip` resolves the package using the user's configured package index and selects the currently available compatible version. 3. If the selected package, one of its transitive dependencies, or the configured package source has been compromised, malicious installation or runtime code is placed in the environment. 4. The dependency executes with the privileges of the user running the installation or invoking the Skill. ### Impact Assessment The potential scope is limited by the privileges of the installing user or Skill process. A compromised dependency could read accessible files and credentials, alter the Python environment, execute network requests, or tamper with OCR inputs and results. No evidence of an existing malicious package or direct privilege escalation was found in the audited project.
Remediation
## Remediation Suggestions 1. Create a reviewed requirements file with exact versions: ```text requests==<reviewed-version> ``` 2. Generate and record hashes for the package and all transitive dependencies. 3. Install with hash verification: ```bash python -m pip install --require-hashes -r requirements.txt ``` 4. Use a trusted package index explicitly and prevent unintended fallback to untrusted extra indexes. 5. Periodically review and update pinned versions after vulnerability and compatibility testing. 6. Run installation and the Skill in an isolated virtual environment with only the filesystem and network access required for OCR.
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (21)

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
INITIAL_RETRY_DELAY = 1    # 初始等待时间(秒)
# --------------------
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
INITIAL_RETRY_DELAY = 1    # 初始等待时间(秒)
# --------------------
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
INITIAL_RETRY_DELAY = 1    # 初始等待时间(秒)
# --------------------
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
96% confidence
Finding
The skill performs sensitive actions implied by its documentation and dependencies: reading local files, invoking Python/shell, and transmitting data to a remote API, yet it declares no explicit tool scope or permission boundaries. In an agent environment, this can cause overbroad execution authority and unclear consent around accessing local images and sending bank-card data off-host.

Natural-Language Policy Violations

Medium
Confidence
86% confidence
Finding
The file’s natural-language instructions, warnings, and invocation examples are presented exclusively in Chinese. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly documented and justified, which is not stated here.

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
97% confidence
Finding
The skill is designed to send bank-card images and extracted data to an external endpoint at api.scnet.cn. Because the content includes highly sensitive financial information, external transmission materially increases privacy, compliance, and data-exposure risk, even though the documentation does disclose it.

External Transmission

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

### 输出
Confidence
96% confidence
Finding
The configurable API base means sensitive bank-card images may be transmitted over the network, and allowing the base URL to be modified can expand the exfiltration surface beyond the intended provider if misconfigured or tampered with. In the context of bank-card OCR, this raises the stakes because the uploaded material contains financial identifiers and cardholder information.

Natural-Language Policy Violations

Medium
Confidence
87% confidence
Finding
The file’s instructional content is entirely in Chinese and presents the field description in a single fixed language. Under the policy, forcing a specific language without user opt-in or documented justification is a natural-language policy violation.

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
81% confidence
Finding
The skill is designed to send uploaded bank card documents to an external service endpoint, creating a real external data exfiltration path for sensitive cardholder information. In the context of a bank-card OCR skill, this is more dangerous than ordinary OCR because the transmitted content includes financial identifiers and personally identifiable information, and the docs do not establish trust boundaries or safeguards for third-party processing.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The documentation instructs users to upload bank card images and OCR content to a third-party remote API, which inherently involves transmission of highly sensitive personal and financial data. It provides no privacy notice, retention limits, encryption/storage handling details, consent requirements, or restrictions on using PDFs/archives, increasing the risk of unauthorized disclosure, regulatory noncompliance, and excessive data exposure.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The module docstring and user-facing usage/output descriptions are entirely in Chinese, and the script later emits Chinese-only prompts and errors. There is no indication that language selection is optional or that the skill is explicitly limited to a Chinese-only regional/compliance context, which can violate language/locale policy requirements.

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
93% confidence
Finding
The skill sends user-supplied bank card images and extracted card data to an external third-party OCR API at api.scnet.cn. Because bank cards contain highly sensitive financial data, external transmission materially increases privacy and data-exposure risk, especially if users are not clearly informed and no minimization or consent controls are enforced.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The description states the skill supports only '中国大陆银行卡' (Mainland China bank cards), which imposes a locale restriction in natural language. The file does not provide user choice, opt-in, or a documented justification that this is a region-specific compliance or business constraint.

Natural-Language Policy Violations

Low
Confidence
80% confidence
Finding
This markdown file is primarily written in Chinese but also contains untranslated English phrases such as version section labels and update notes. Under the language/locale policy rule, forcing a particular language presentation without opt-in or justification can be a natural-language policy concern.

Intent-Code Divergence

Low
Confidence
95% confidence
Finding
The manifest says this skill recognizes mainland China bank cards and extracts card details, but the README from L05 onward is generic GitLab boilerplate about repository setup, collaboration, and template editing. This documentation does not describe the skill and therefore diverges from the stated intent of the project documentation.

Intent-Code Divergence

Low
Confidence
92% confidence
Finding
SKILL.md 的主体内容多次说明该技能是“银行卡识别 OCR 技能”,且 ocrType 仅允许 BANK_CARD、功能特性也只列出银行卡识别。但 tags 包含“证件识别”“发票识别”,正文 L027 还写到“提取文字及票据信息”,这会让使用者误以为该技能支持与银行卡无关的识别范围。

Intent-Code Divergence

Low
Confidence
86% confidence
Finding
该技能整体声明为银行卡 OCR,但示例命令使用 `/path/to/invoice.jpg`,而自然语言示例又使用 `/Downloads/id.jpg`。这与“银行卡识别”用途直接冲突,属于文档示例对技能意图的错误表达,而不是单纯信息缺失。

Static analysis

No suspicious patterns detected.