Back to skill

Security audit

financial_bill_ocr

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent OCR purpose, but it needs review because it can upload sensitive financial documents and the configured API token to a configurable network endpoint with weak file and destination scoping.

Install only in an environment where sending financial documents to Scnet's remote OCR service is approved. Keep `SCNET_API_BASE` pinned to the documented HTTPS endpoint, use a limited API token, avoid regulated or highly confidential documents unless external processing is authorized, and confirm the exact file path before each upload.

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:78
Finding

Arbitrary readable files and API credentials can be transmitted to a configurable server

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:78, 86-112, 189
Vulnerability Type: Unrestricted upload destination and insufficient file validation
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):
    api_base = config['SCNET_API_BASE']
    api_key = config['SCNET_API_KEY']
    url = f"{api_base}/ocr/recognize"

    # Check whether the file exists
    if not os.path.isfile(file_path):
        sys.exit(f"Error: file does not exist - {file_path}")

    # Automatically detect the MIME type
    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
            )

The path supplied through the command line is used directly:

python
ocr_type = sys.argv[1]
file_path = sys.argv[2]

config = load_config()
recognize_with_retry(ocr_type, file_path, config)

Technical Analysis

Uploading the selected financial document to SCNet is necessary for the declared cloud OCR functionality and is explicitly disclosed in SKILL.md. However, the implementation does not constrain SCNET_API_BASE to the documented SCNet HTTPS origin.

The configured base URL is concatenated with /ocr/recognize, after which both the bearer credenti ...[truncated 2486 chars]

Remediation
View remediation

Remediation Suggestions

  1. Allowlist the exact expected API scheme, hostname, port, and base path, such as https://api.scnet.cn/api/llm/v1.
  2. Reject non-HTTPS destinations and URLs containing embedded credentials, fragments, unexpected ports, or unapproved hostnames.
  3. If custom endpoints are genuinely required, make them an explicit opt-in feature and use endpoint-specific credentials rather than sending the SCNet credential to them.
  4. Disable redirects for authenticated upload requests, or validate every redirect destination before forwarding credentials or file content.
  5. Restrict accepted input to documented formats using an extension allowlist and content-signature inspection rather than relying only on mimetypes.guess_type.
  6. Enforce a reasonable maximum file size before opening or uploading the file.
  7. Resolve the supplied path and, where operationally possible, restrict access to a user-approved upload directory.
  8. Require explicit confirmation that identifies both the resolved file path and destination host before transmitting sensitive financial documents.
  9. Document retention, privacy, and regulatory implications of sending financial records to the third-party service.
  10. Add automated tests confirming rejection of attacker-controlled origins, plaintext HTTP endpoints, redirects to other origins, unsupported file types, and oversized files.

T08 · Insecure Dependencies

Note
Location
SKILL.md:67
Finding

Unpinned third-party dependency installation reduces supply-chain integrity

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:67-71
Vulnerability Type: Unpinned runtime dependency
Risk Level: Low

Vulnerable Code

bash
pip install requests

Technical Analysis

The installation instructions retrieve the latest version of requests and its transitive dependencies from the package index configured in the user's environment. No exact version, integrity hash, lock file, or approved index is specified.

Consequently, the code installed for the Skill can vary over time and may differ from the dependency version that was reviewed. The instruction also inherits user-level or global pip configuration, including potentially untrusted package mirrors.

This is a supply-chain hardening deficiency rather than evidence that the current requests package is malicious.

Attack Path

  1. A user follows the documented pip install requests instruction.
  2. pip resolves the package and transitive dependencies using the environment's configured package index or mirror.
  3. A compromised release, compromised index, or maliciously configured mirror supplies altered package content.
  4. The package is installed into the selected Python environment.
  5. Malicious dependency code can execute during installation or when scripts/main.py imports and uses the package.

The attack depends on compromise or manipulation of the dependency distribution channel; the audited project does not itself retrieve or execute a separate remote payload.

Impact Assessment

Compromised dependency code would execute with the privileges of the user installing or invoking the Skill. It could access files and environment data available to that account, intercept the OCR document and API token, alter network requests, or modify the Python environment.

Installing into a global or privileged environment could increase the affected scope, while installation in an isolated, unprivileged virtual environment wou ...[truncated 12 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add a dependency file containing an audited, exact requests version and exact versions for transitive dependencies.
  2. Generate and verify cryptographic hashes, and install with pip --require-hashes.
  3. Use a lock-file workflow that records the complete resolved dependency graph.
  4. Install dependencies from an approved HTTPS package index or controlled internal mirror.
  5. Perform installation inside a dedicated, unprivileged virtual environment rather than the system Python environment.
  6. Add automated dependency vulnerability and integrity scanning to the release process.
  7. Establish a documented update process so pinned versions receive reviewed security upgrades.
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)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/main.py (reported line 20)May include surrounding context.

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

# --- 新增:重试配置 ---
MAX_RETRIES = 3            # 最大重试次数

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 63)May include surrounding context.

md
# --------------------

def load_config():
    """从 .env 文件加载配置,若文件不存在则抛出友好错误"""
    if not ENV_FILE.exists():
        error_msg = (
            "\n===============================================\n"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SKILL.md (reported line 125)May include surrounding context.

md
# --------------------

def load_config():
    """从 .env 文件加载配置,若文件不存在则抛出友好错误"""
    if not ENV_FILE.exists():
        error_msg = (
            "\n===============================================\n"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/main.py (reported line 29)May include surrounding context.

python
# --------------------

def load_config():
    """从 .env 文件加载配置,若文件不存在则抛出友好错误"""
    if not ENV_FILE.exists():
        error_msg = (
            "\n===============================================\n"

Autonomous Decision Making

Medium
Category
Excessive Agency
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.

Content

Scanner excerpt · README.md (reported line 38)May include surrounding context.

md
* [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)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill documentation indicates capabilities to read local files, invoke Python/shell, and send data over the network, but it declares no explicit tool scope such as permissions or allowed-tools. This creates a least-privilege failure: an agent may execute the skill with broader-than-necessary access, increasing the chance of unintended file access or data exfiltration beyond the user's intent.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

The skill explicitly uploads local financial document images to a third-party OCR service. Because these documents can contain bank details, invoices, customs data, and other regulated or sensitive information, transmission to an external service materially increases confidentiality, privacy, and compliance risk if used in an environment where such exfiltration is not approved.

Content

Scanner excerpt · SKILL.md (reported line 27)May include surrounding context.

md
---
# Sugon-Scnet 金融单据识别 OCR 技能

本技能封装了金融单据识别的 OCR 服务,通过单一接口即可调用金融单据识别能力。识别过程中,**本地文件将被上传至第三方 OCR 服务 `https://api.scnet.cn/`** 进行处理,请确保图片中不包含高度敏感或受合规保护的信息,或确认当前环境允许外传。

## 功能特性

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 55)May include surrounding context.

SCNET_API_KEY=your_scnet_api_key_here

API 基础地址(一般无需修改)

SCNET_API_BASE=https://api.scnet.cn/api/llm/v1

text
2. 添加:`SCNET_API_KEY=你的密钥`
3. 设置文件权限为 600(仅所有者可读写)

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 107)May include surrounding context.

SCNET_API_KEY=your_scnet_api_key_here

API 基础地址(一般无需修改)

SCNET_API_BASE=https://api.scnet.cn/api/llm/v1

text
2. 添加:`SCNET_API_KEY=你的密钥`
3. 设置文件权限为 600(仅所有者可读写)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The usage section specifies a Chinese example utterance and states the AI will auto-trigger from description keywords, but nowhere offers users a language or locale choice. This can violate language/locale policy when the skill implicitly requires Chinese interaction without explicit opt-in or a documented region-specific justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This markdown file documents extraction of sensitive data such as bank account numbers, payment passwords, bill numbers, customs data, and personal or organizational financial identifiers. Under the markdown-specific warning criterion, the description omits any notice about handling, storage, privacy, or downstream use of this sensitive information, which could affect user data privacy.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The skill relies on a remote HTTPS API at api.scnet.cn, which means document contents are sent outside the local environment for processing. In the context of a financial bill OCR skill, that external transmission materially increases risk because the documents may contain PII, financial account data, trade records, and other confidential business information.

Content

Scanner excerpt · references/api-docs.md (reported line 4)May include surrounding context.

md
# Sugon-Scnet OCR API 文档摘要

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

## 请求头
- `Content-Type: multipart/form-data`

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation describes uploading highly sensitive financial and identity-document images to a third-party OCR endpoint, and the sample response includes personal data such as name, address, birth date, and ID number. There is no accompanying warning, consent requirement, retention guidance, or disclosure of external processing, which creates a real privacy and compliance risk when this skill is used on regulated documents.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/main.py (reported line 45)May include surrounding context.

python
"   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)

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/main.py (reported line 152)May include surrounding context.

python
"   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)

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

The code is designed to send documents to an external service at api.scnet.cn, which constitutes outbound data transfer of potentially sensitive financial records. In this skill's context, external transmission materially increases privacy, regulatory, and data-exposure risk, especially if used in enterprise or regulated settings.

Content

Scanner excerpt · scripts/main.py (reported line 78)May include surrounding context.

python
)
        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):

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script uploads the user-specified document file to a third-party OCR endpoint, and the skill processes highly sensitive financial documents. There is no explicit runtime consent flow, privacy notice, or restriction on document sensitivity before transmission, creating a real confidentiality and compliance risk if users assume processing is local.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest grants shell execution to an OCR-focused skill even though the metadata only describes document recognition and structured extraction. Shell access materially expands the attack surface because any downstream implementation could execute arbitrary local commands, access host tooling, or combine shell and file/network permissions for broader compromise without a stated business need.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file uses Chinese exclusively for headings and change descriptions, with no indication that the skill is region-specific or that users can opt into this locale. Under the language/locale policy rule, forcing a specific language without opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
72% confidence
Finding

The file's headings and descriptive text are entirely in Chinese, and there is no indication that users may choose another language or locale. If this skill documentation dictates or implies a fixed language experience without opt-in, it may conflict with the language-choice policy.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest description is entirely in Chinese and provides no indication that other languages are supported or that this locale restriction is intentional. For a general-purpose skill manifest, this can create a language policy concern if users are not given an explicit language choice or opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.