T09 · Insecure Skill Coding Practices
- Location
scripts/invoice.py:244- Finding
API Credentials Stored in Plaintext Without Enforced Access Restrictions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill does what it claims: it sends user-selected Chinese invoice files to NetOCR for OCR/verification and can export results, with some privacy and hardening cautions.
Install only if you are comfortable sending invoice contents and NetOCR API credentials to netocr.com. Keep the skill directory private, avoid committing config.json or generated result JSON files, rotate credentials if exposed, and treat exported spreadsheets as untrusted unless formula-like invoice fields are sanitized.
scripts/invoice.py:244API Credentials Stored in Plaintext Without Enforced Access Restrictions
scripts/export_invoice.py:198Spreadsheet Formula Injection Through Untrusted Invoice Data
The skill documents capabilities that involve local file access, credential storage, and outbound network requests, but it does not declare any explicit tool scope such as allowed-tools or permissions. This creates a mismatch between what the skill can cause an agent to do and what is transparently constrained, increasing the risk of over-privileged execution, unintended file writes, or silent transmission of invoice data and secrets to third-party services.
The trigger phrases are broad enough to match many ordinary invoice-related requests, including export, accounting, and batch-processing tasks, which could cause the skill to activate when the user did not intend OCR, verification, or third-party transmission. In this context, accidental activation is more dangerous because invoices often contain sensitive financial and personal data, and the skill's default behavior includes networked verification.
The skill transmits invoice images and extracted invoice metadata to external OCR and verification endpoints, but the script does not provide an explicit warning or consent gate before uploading potentially sensitive financial and personal data. In this context, invoices can contain tax IDs, names, addresses, banking data, and transaction details, so silent disclosure to a third party materially increases privacy and compliance risk.
The script persists API key and secret to config.json on disk without warning the user that secrets will be stored locally. If the working directory is shared, backed up, committed, or readable by other users/processes, these credentials can be exposed and then abused for unauthorized API use or billing consumption.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
"img": "", # 空图片,接口会返回错误但能验证认证
"format": "json",
}
resp = requests.post(API_RECOGNIZE, data=payload, timeout=30)
result = resp.json()
# 检测认证错误
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
"typeId": "20090",
"format": "json",
}
resp = requests.post(API_RECOGNIZE, data=payload, timeout=60)
resp.raise_for_status()
result = resp.json()
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
payload[opt] = val
try:
resp = requests.post(API_VERIFY, data=payload, timeout=60)
resp.raise_for_status()
result = resp.json()
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
# ──────────────────────────────────────────────
# 处理单张发票
# ──────────────────────────────────────────────
def process_single(image_path, key, secret, do_verify=False,
do_export=False, template=None, output_dir=None):
image_path = Path(image_path)
print(f"\n[FILE] {image_path.name}")
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
# ──────────────────────────────────────────────
# 处理单张发票
# ──────────────────────────────────────────────
def process_single(image_path, key, secret, do_verify=False,
do_export=False, template=None, output_dir=None):
image_path = Path(image_path)
print(f"\n[FILE] {image_path.name}")
The docstring and all user-facing prompts are written only in Chinese, which imposes a specific language on users with no opt-in or alternative. Under the policy, language constraints should either be optional for the user or explicitly justified as region-specific.
The natural-language description and operational guidance are entirely specified in Chinese and present the skill as a Chinese-only interaction flow, with no opt-in or language choice for the user. This can violate language or locale policy when a skill constrains interaction language without explicit justification or user selection.
The dependency on requests is only lower-bounded and not pinned, so installations can resolve to different versions over time. This creates supply-chain risk and makes it impossible to guarantee that a deployment is not using a vulnerable or breaking release, especially for a skill that likely performs network requests to OCR/verification services.
requests>=2.28.0
openpyxl>=3.1.0
Pillow>=9.0.0
requests has multiple published advisories, and because the manifest does not pin a version, there is no way to verify whether the resolved version is affected. In a skill that likely sends invoice data to external services, a vulnerable HTTP client could contribute to credential leakage, TLS verification issues, or other transport-layer weaknesses depending on the installed version.
openpyxl is specified as >=3.1.0 rather than an exact version, so builds are not reproducible and may silently consume a later vulnerable or incompatible release. Because this skill exports invoice data and spreadsheets, dependency integrity matters and a compromised parser/writer library could affect sensitive financial workflows.
requests>=2.28.0
openpyxl>=3.1.0
Pillow>=9.0.0
openpyxl has historical security advisories, and without version pinning the installed release cannot be verified as safe. Given the skill's invoice/export context, uncertainty around the spreadsheet library increases risk if the application handles untrusted workbook content or generates files consumed by other systems.
Pillow is also unpinned, which means environments may install different releases with differing security posture. Since this skill likely processes user-supplied invoice images, using an unpinned image library increases exposure to future or known image-parsing vulnerabilities.
requests>=2.28.0
openpyxl>=3.1.0
Pillow>=9.0.0
Pillow has numerous historical vulnerabilities, including issues in image parsing, and the unpinned requirement makes it impossible to confirm the deployed version is unaffected. This is more concerning in this skill because invoice OCR commonly ingests untrusted image files, making image-decoder flaws a realistic attack surface.
The primary natural-language documentation is entirely in Chinese, including the module description and template names, with no indication that users may choose another language or that the tool is region-locked by policy. This can violate a language/locale policy when a skill imposes a specific language without explicit opt-in or documented justification.
The script's docstring, CLI prompts, help text, and user-facing output are all in Chinese, which effectively forces a specific language experience. There is no opt-in or documented justification that this is a region- or locale-specific tool limited to Chinese-speaking users.