T09 · Insecure Skill Coding Practices
- Location
scripts/extract-invoice.py:43- Finding
Automatic Transmission of Sensitive Invoice Images to a Third-Party OCR Service
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This invoice OCR skill is purpose-aligned, but users should understand that invoice images and metadata may be sent to external OCR or tax-verification services.
Install only if you are comfortable sending invoice documents and invoice metadata to the configured OCR, AI vision, tax-verification, or Feishu systems. Use narrowly scoped API keys, avoid processing highly sensitive invoices without approval, and prefer adding an explicit confirmation step before cloud OCR or external sync.
scripts/extract-invoice.py:43Automatic Transmission of Sensitive Invoice Images to a Third-Party OCR Service
scripts/extract-invoice.py:39API Credentials and Access Tokens Embedded in Request URLs
The script embeds the Baidu client secret directly into the token request URL query string. Secrets in URLs are more likely to be exposed through proxy logs, monitoring systems, browser/history tooling, or exception traces than secrets sent in a request body or safer auth mechanism.
# 获取 access_token
token_url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={api_key}&client_secret={secret_key}"
token = requests.post(token_url).json().get("access_token")
# 调用发票识别
with open(image_path, "rb") as f:
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
}
try:
resp = requests.post(
"https://inv.chinatax.gov.cn/api/verify",
json=payload,
headers={"Authorization": f"Bearer {api_key}"},
整体上,代码与描述的大部分核心能力是匹配的:单张/批量识别、字段提取、费用分类、税务验真、导出 Excel 都有实现,因此主功能方向一致。但描述中包含若干未实现或被夸大的能力,属于描述与行为不完全一致。最明显的是“可写入飞书多维表格或报销系统”,代码只支持导出 Excel/JSON,没有任何飞书或外部报销系统集成。另外,描述强调“发票/票据图片”这一较广范围,而实际 OCR 核心是百度 VAT 发票接口,功能更像增值税发票识别器,虽然可处理图片/PDF文件,但并未体现通用票据模板识别。基于这些未声明实现差异,应判定为存在 mismatch。
声明的核心能力是“自动识别发票/票据图片并提取字段”,但该代码块的实际职责是后处理:从 JSON 文件加载已识别结果,过滤重复项,组装报销单数据,输出 JSON 草稿和费用汇总。代码没有任何图像/PDF 处理、OCR 调用、发票真伪校验接口调用、批量识别逻辑、飞书多维表格写入或 Excel 导出实现。虽然‘将发票数据写入飞书报销系统’与声明中部分场景有关,但这里只是生成本地 JSON 数据结构,且注释明确说明实际提交 API 需另行配置。因此,代码的主要用途与声明的主要用途存在实质性偏差,应判定为不匹配。
The skill instructs use of local files, environment-provided API keys, and external OCR/verification services, but it does not declare any explicit tool scope or permissions boundary. In an agent environment, missing scope declarations can allow broader-than-expected access to network, filesystem, or secrets, increasing the chance of unintended data exposure or misuse of credentials.
Invoice data commonly contains sensitive financial and personal/business identifiers, and the skill promotes writing that data into Feishu Bitable or reimbursement systems without warning users about transmission, retention, or access control implications. Users may unknowingly authorize disclosure of tax IDs, invoice numbers, or amounts to third-party services or broader internal audiences.
The skill explicitly suggests sending invoice images to an AI vision model when OCR API keys are unavailable, but it does not warn that uploaded documents may be processed by an external model provider. Because invoices often contain personally identifiable and financial information, silent fallback to external AI processing creates a meaningful confidentiality and compliance risk.
This markdown file contains user-facing instructions only in Chinese, and there is no indication that the skill is region-specific or that users can opt into this language. Under the policy, forcing a specific language without user choice is a natural-language policy violation.
This markdown file contains only Chinese-language instructions and examples, with no indication that the user can opt into another language or that the skill is intentionally limited to a Chinese-speaking or China-specific audience. Under the policy rule, forcing a specific language without user opt-in is a natural-language policy concern.
Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.
missing = []
for pkg in ["PIL", "requests", "pandas"]:
try:
__import__(pkg if pkg != "PIL" else "PIL.Image")
except ImportError:
missing.append(pkg.replace("PIL", "pillow"))
if missing:
Invoice images commonly contain sensitive financial and personal data, and this function uploads the full image to a third-party OCR service without any explicit user-facing disclosure or consent flow. In a skill designed for automated invoice processing, silent transmission increases privacy and compliance risk because users may reasonably expect local extraction unless told otherwise.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
img_b64 = base64.b64encode(f.read()).decode()
url = f"https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice?access_token={token}"
resp = requests.post(url, data={"image": img_b64}).json()
if "words_result" not in resp:
raise ValueError(f"百度 OCR 返回错误: {resp}")
The verification function sends invoice identifiers, date, and amount to a remote service without a user-facing warning. Although tax verification is expected to contact an external system, the absence of clear notice and consent creates privacy and compliance concerns for financial records.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
}
try:
resp = requests.post(
"https://inv.chinatax.gov.cn/api/verify",
json=payload,
headers={"Authorization": f"Bearer {api_key}"},
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
}
try:
resp = requests.post(
"https://inv.chinatax.gov.cn/api/verify",
json=payload,
headers={"Authorization": f"Bearer {api_key}"},
The skill content is presented entirely in Chinese and is tailored to Chinese invoice-processing contexts, while not offering any language selection or opt-in. This can be a locale constraint, but the file does not clearly document it as a justified region-specific limitation in the description header.
The entire reference document is written only in Chinese and provides no indication that users may choose another language or locale. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy concern unless the locale restriction is explicitly documented and justified.
User-facing natural-language strings, descriptions, help text, and status messages throughout the script are presented exclusively in Chinese. There is no indication that users can choose another language or that the Chinese-only restriction is an intentional, documented regional constraint.
The module docstring is entirely in Chinese and presents the skill as a reporting/expense-form tool without any indication that Chinese is optional or required for a specific regional compliance reason. Under the policy rule, forcing a specific language without user opt-in is a natural-language locale violation.
No suspicious patterns detected.