T09 · Insecure Skill Coding Practices
- Location
scripts/upload_oss.py:33- Finding
Authenticated OSS uploads can use plaintext HTTP
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill does what it says, but it uploads business analysis artifacts to OSS using public-style URLs and lacks strong guardrails for transport and sharing.
Install only in a controlled enterprise environment. Use least-privilege database and OSS credentials, require HTTPS OSS endpoints, keep buckets private, prefer signed expiring URLs, avoid broad DingTalk channels, and review whether analysis_context.json may expose internal competitive intelligence before upload.
scripts/upload_oss.py:33Authenticated OSS uploads can use plaintext HTTP
scripts/upload_oss.py:79Stable unsigned object URLs can expose internal analysis artifacts
scripts/run_report.py:13Runtime dependencies are recommended without version or integrity pinning
The supplied code is a local report rendering utility, not an end-to-end scheduled competitor-analysis workflow. Its behavior is limited to formatting a provided report object into Markdown and HTML and saving those files under an output directory. The declared description promises several additional core capabilities—polling crawl triggers, aggregating six months of category data, producing analysis context/report skeletons, uploading outputs to OSS, and sending a DingTalk summary—but none of these appear in the code chunk. Because the actual code's primary purpose is narrower and materially different from the declared end-to-end workflow, this is a description-behavior mismatch.
Referenced artifact was not completely inspected
- `SKILL.md`: skill entry instructions
The skill declares access to environment-provided secrets and describes behaviors involving file writes and network operations, but it does not define any explicit tool scope such as permissions or allowed-tools. In an enterprise automation context, this weakens least-privilege controls and makes it harder for a host to constrain secret access, outbound network use, and file creation.
The skill states that it uploads outputs to OSS and sends summaries to DingTalk, but it does not prominently warn users that generated data will leave the local/runtime boundary. In a workflow handling aggregated competitor, product, review, and QA data, undisclosed external transmission increases the risk of inadvertent data leakage and compliance violations.
The setup guide includes a full DSN with a username/password placeholder and a live-format DingTalk webhook URL alongside OSS access key fields, but it does not warn readers to avoid committing real secrets or to treat these values as sensitive. In a deployment-oriented skill that is meant to be copied into local or workspace configuration, this increases the chance that operators paste real credentials into tracked config files or shared documentation, leading to credential leakage and unauthorized access.
The template mandates Chinese headings and output fields throughout, such as the report title suffix 市场机会分析报告 and multiple required Chinese section/table labels. This imposes a specific language/locale on generated output without indicating user choice or opt-in, which matches the language policy violation criteria.
The generated HTML explicitly sets lang='zh-CN', and the report content is hardcoded in Chinese throughout the file. This imposes a specific language/locale without any visible opt-in or explanation that the skill is intentionally region-specific.
Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.
html_key = oss_uploader.key_for(f"{rel_base}/report.html")
ctx_key = oss_uploader.key_for(f"{rel_base}/analysis_context.json")
uploaded = {
"report_md": oss_uploader.upload_file(rendered.markdown_path, md_key).public_url,
"report_html": oss_uploader.upload_file(rendered.html_path, html_key).public_url,
"analysis_context": oss_uploader.upload_file(context_path, ctx_key).public_url,
}
Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.
html_key = oss_uploader.key_for(f"{rel_base}/report.html")
ctx_key = oss_uploader.key_for(f"{rel_base}/analysis_context.json")
uploaded = {
"report_md": oss_uploader.upload_file(rendered.markdown_path, md_key).public_url,
"report_html": oss_uploader.upload_file(rendered.html_path, html_key).public_url,
"analysis_context": oss_uploader.upload_file(context_path, ctx_key).public_url,
}
Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.
html_key = oss_uploader.key_for(f"{rel_base}/report.html")
ctx_key = oss_uploader.key_for(f"{rel_base}/analysis_context.json")
uploaded = {
"report_md": oss_uploader.upload_file(rendered.markdown_path, md_key).public_url,
"report_html": oss_uploader.upload_file(rendered.html_path, html_key).public_url,
"analysis_context": oss_uploader.upload_file(context_path, ctx_key).public_url,
}
These lines transmit report artifacts containing aggregated product, review, and Q&A data to a remote object storage service. Although the behavior is part of the workflow, this file itself provides no user-facing print, comment, or docstring warning that collected data will be uploaded externally.
The script uploads analysis_context.json, which contains the full report_payload and host_analysis_context derived from database contents, then stores and shares its public URL. Unlike a human-readable report, this structured context may expose more raw or comprehensive internal data than necessary, increasing the chance of unintended disclosure if the OSS object is publicly accessible or broadly shared.
uploaded = {
"report_md": oss_uploader.upload_file(rendered.markdown_path, md_key).public_url,
"report_html": oss_uploader.upload_file(rendered.html_path, html_key).public_url,
"analysis_context": oss_uploader.upload_file(context_path, ctx_key).public_url,
}
summary = build_summary_markdown(
This code posts the generated summary, which includes analysis derived from collected data, to DingTalk over the network. The file lacks a visible disclosure near execution that report content is being shared via webhook, beyond configuration checks for environment variables.
The function builds output with fixed Chinese labels such as 品类, 执行摘要, and 关键发现, which imposes a specific language choice on all users. There is no option to select locale or language, and no documented justification that this is a region-specific skill.
This code performs a network operation that uploads a local file to Alibaba Cloud OSS, which can transmit user or system data off-host. While the class docstring describes the uploader's purpose, the upload path itself has no confirmation prompt, print/log statement, or inline warning disclosing that the file will be sent to a remote service.
The instruction to use 未采集 or 待补充 mandates specific Chinese-language output tokens. This is a natural-language locale constraint, and the document does not indicate user opt-in or explain that the skill is intentionally limited to a Chinese-language workflow.
The heading and example content switch to Chinese (for example, '示例' and '自动分析任务') while the rest of the setup guide is in English. This can amount to a language/locale policy issue because the file imposes mixed-language content without user opt-in or justification.
The renderer creates a new output directory and writes both markdown and HTML report files, which may persist potentially sensitive report contents to local storage. There is no confirmation prompt, visible log/print statement, or inline warning near the write operations to disclose that user data will be saved to disk.
Natural-language strings in this file, including dependency errors and CLI descriptions, are presented only in Chinese. That enforces a locale/language choice without opt-in or documented justification, which matches the language-policy violation criterion.
The argument parser help text is entirely Chinese, and later runtime output is also Chinese-only. This makes the tool's user interaction language fixed rather than user-selectable.
The code sends JSON payload data to an external DingTalk webhook via urlopen, which can transmit user-provided report titles, summaries, findings, and links off-system. There is no visible confirmation prompt, user-facing log/print, or inline disclosure in this file warning that content will be sent to a remote service.
The exception text is hard-coded in Chinese, which imposes a specific language on users regardless of their locale or preference. The file does not offer a language choice or document that this skill is intentionally Chinese-only for a region-specific use case.
No suspicious patterns detected.