Back to skill

Security audit

ocr-bankcard-xiangyun

Security checks for vulnerabilities and agentic risk

Overview

This skill performs the advertised bank-card OCR task, but it handles payment-card images, OCR results, and API credentials in ways that need careful review before installation.

Install only if you are comfortable uploading bank-card images to Xiangyun/netocr.com and storing OCR credentials locally. Prefer using test or non-production card images, run recognition with --no-save when possible, protect or delete generated JSON files, avoid printing or logging full JSON results, and do not open exported spreadsheets from untrusted inputs without sanitizing formula-like values.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/config_manager.py:35
Finding

Plaintext API Credential Storage and Disclosure

Content
View full analysis
None: """将 key 和 secret 持久化写入 config.json。""" data = load_config() data["key"] = key.strip() data["secret"] = secret.strip() with open(CONFIG_PATH, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"[OK] 配置已保存至: {CONFIG_PATH}") ``` ```python if args.command == "load": cfg = load_config() configured = is_configured(cfg) output = { "configured": configured, "key": cfg.get("key", ""), "secret": cfg.get("secret", ""), "config_path": CONFIG_PATH, } print(json.dumps(output, ensure_ascii=False, indent=2)) ``` ### Technical Analysis The credential manager writes the OCR API key and secret directly to `config.json` without encryption or explicit restrictive file permissions. The effective permissions therefore depend on the process umask and may allow other local users or processes to read the file. Credentials are also accepted through command-line arguments, as documented by the Skill, which can expose them through shell history, process inspection, command logging, or orchestration telemetry. The `load` command then prints both credentials verbatim to standard output. This unnecessarily increases the number of disclosure channels and exceeds the minimum access needed to verify whether the Skill is configured. No live credentials were embedded in the reviewed package; the shipped `config.json` contains empty values. ### Attack Path 1. A user runs the documented `save --key ... --secret ...` command. 2. The shell records the credentials in command history, or another local process observes the command-line arguments. 3. The manager writes the credentials to `config.json` using ...[truncated 625 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/recognize.py:281
Finding

Full Bank-Card Data Is Persisted and Printed Without Adequate Protection

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/export.py:96
Finding

Spreadsheet Formula Injection in CSV and Excel Exports

Content
View full analysis
dict: """将识别结果转换为可导出的行数据。""" row = {} for key, label in FIELDS: row[label] = record.get(key, "") row["识别时间"] = record.get("recognized_at", datetime.now().strftime("%Y-%m-%d %H:%M:%S")) row["状态"] = "成功" if record.get("success", True) else f"失败: {record.get('error_message', '')}" return row ``` CSV output writes these values without formula neutralization: ```python def export_csv(records: list, output_path: str) -> None: rows = [to_row(r) for r in records] if not rows: print("[WARN] 无数据可导出", file=sys.stderr) return fieldnames = list(rows[0].keys()) with open(output_path, "w", newline="", encoding="utf-8-sig") as f: writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() writer.writerows(rows) ``` Excel output likewise assigns the values directly to cells: ```python for row_idx, row in enumerate(rows, start=2): for col_idx, name in enumerate(fieldnames, start=1): ws.cell(row=row_idx, column=col_idx, value=row.get(name, "")) ``` ### Technical Analysis Exported values originate from OCR results, provider responses, cached JSON files, batch input files, or standard input. These sources cannot be assumed trustworthy. Spreadsheet applications may interpret text beginning with characters such as `=`, `+`, `-`, or `@` as a formula rather than inert data. The CSV writer correctly quotes CSV syntax but does not prevent spreadsheet formula evaluation. Similarly, assigning a formula-prefixed string through `openpyxl` can result in a formula cell. An attacker can therefore place a malicious formula in an image-visible field or directly in imported JSON and rely ...[truncated 1427 chars]
Remediation
View remediation
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 (19)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents the skill primarily as OCR, but the documented behavior also includes batch ingestion, arbitrary-path exports, and Excel generation. That mismatch can mislead reviewers and users about the real data-handling footprint, especially since extracted bank card data may be copied into additional files and directories beyond the recognition step.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The load command prints the stored API key and secret in plaintext to stdout. In this skill context, those credentials grant access to a third-party OCR service and may be captured by terminal history, logs, calling agents, or other local observers, enabling unauthorized API use and account abuse.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill sends bank card images or base64 image data to a third-party OCR service, which necessarily discloses highly sensitive financial information outside the local environment. Even though HTTPS is used, the core risk is data exposure to an external processor without prominent user warning, consent flow, retention notice, or minimization controls.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill instructs the agent to read local files, write config and result files, and send data to external network endpoints, but it does not declare any tool scope or permissions boundary. This increases the risk of over-broad execution because operators and users are not clearly informed that the skill can access the filesystem and transmit sensitive bank card data off-host.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This skill processes highly sensitive financial data and sends bank card images and extracted fields to an external OCR provider, yet the documentation does not prominently warn users about third-party transmission. In this context, lack of disclosure is dangerous because users may unknowingly upload regulated or confidential cardholder data to a remote service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation instructs users to transmit highly sensitive bank card images plus API credentials to a third-party OCR provider, but it provides no privacy notice, consent guidance, retention warning, or handling constraints. Because bank card images can contain PANs, cardholder names, expiry dates, and issuer metadata, this creates meaningful confidentiality and compliance risk even if the transmission is over HTTPS.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The sample code operationalizes sending raw bank card images and API secrets to a remote OCR endpoint without any accompanying warning about third-party disclosure, storage, logging, or downstream processing. This is especially sensitive because the examples normalize direct handling of payment-card data and credentials, increasing the chance that developers integrate the flow without appropriate user notice or minimization controls.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This example performs external transmission of a Base64-encoded bank card image and API credentials to a remote service. Although this is the intended functionality of the OCR integration, it still represents a real security/privacy concern because the data includes highly sensitive financial information and the documentation does not bound or warn about that exposure.

Content

Scanner excerpt · references/api_docs.md (reported line 119)May include surrounding context.

md
with open("bankcard.jpg", "rb") as f:
    img_b64 = base64.b64encode(f.read()).decode("utf-8")

resp = requests.post(
    "https://netocr.com/api/recogliu.do",
    data={
        "img": img_b64,

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This example uploads a bank card image file and credentials to an external OCR endpoint. The transmission itself is not hidden or obfuscated, but in the context of bank card recognition it exposes sensitive payment-card data to a third party and may encourage unsafe adoption if developers are not warned about privacy, compliance, and retention implications.

Content

Scanner excerpt · references/api_docs.md (reported line 138)May include surrounding context.

md
import requests

with open("bankcard.jpg", "rb") as f:
    resp = requests.post(
        "https://netocr.com/api/recog.do",
        files={"file": ("bankcard.jpg", f)},
        data={

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module docstring states that python config_manager.py reset clears the configuration with a required second confirmation (需二次确认). However, the reset subcommand is defined and executed directly with no prompt, confirmation flag, or safety check before overwriting config.json. This is an active contradiction between the documented intent and the implemented behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The header comment states that reset requires secondary confirmation, but the implementation immediately clears stored key and secret when the command is invoked. This is a destructive operation affecting persisted configuration and lacks any runtime confirmation prompt or equivalent safeguard.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This Python file contains natural-language documentation entirely in Chinese, and the CLI description/help strings are also Chinese-only. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly justified, which is not stated here.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script automatically persists OCR output to a sibling JSON file by default, even though the top-level usage text emphasizes stdout/stderr output. Because the data includes highly sensitive bank card details and potentially cardholder name, this creates an unexpected local data-at-rest footprint that can be discovered by other users, backup tools, or later processes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code writes extracted OCR results, including card number, holder name, and bank metadata, to a JSON file automatically after success. This creates a secondary sensitive artifact on disk without a clear warning, increasing the risk of exposure through shared directories, endpoint indexing, backups, or later compromise of the host.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The workflow stores API credentials in a local config.json inside the skill directory, but the documentation does not adequately warn about plaintext secret persistence and local exposure risks. On shared systems or poorly permissioned directories, another user or process could recover the OCR key and secret and abuse the account.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill auto-saves recognition results as JSON alongside the source image, but this persistence of extracted bank card data is not surfaced as a meaningful warning. That can create unintended local data sprawl, exposing card numbers and issuer details to other users, backup systems, sync tools, or later accidental disclosure.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The script's help text and status messages are entirely in Chinese, and there is no indication that the user can select another language or that the tool is intentionally restricted to a Chinese-speaking context. This can violate language/locale policy when users are not given an opt-in or justified locale limitation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

User-facing descriptions, errors, and output strings are entirely in Chinese, and the script does not provide any language selection or state that it is intentionally restricted to a Chinese-speaking or region-specific audience. Under the policy, forcing a specific language without opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The documented behavior says results are printed, but the program actually saves them by default unless --no-save is passed. This mismatch is security-relevant because it prevents informed consent around local persistence of sensitive financial OCR data and makes accidental disclosure more likely.

Content

No source excerpt is available for this finding.