T09 · Insecure Skill Coding Practices
- Location
amazon_scraper.py:86- Finding
API Credential Exposed Through URL Query Parameters
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a coherent Amazon scraping skill, but it needs Review because it uses an Apify API key and third-party scraping with weak disclosure and insecure setup guidance.
Install only if you are comfortable sending Amazon search terms and scraping activity to Apify. Use an isolated virtual environment, keep the Apify token in an environment variable or secret manager, avoid hardcoding it, do not use the cron example unless you really want scheduled scraping, and treat generated spreadsheets as untrusted external-content reports.
amazon_scraper.py:86API Credential Exposed Through URL Query Parameters
amazon_scraper.py:235Spreadsheet Formula Injection Through Scraped Product Data
SKILL.md:116Documentation Encourages Hardcoding an API Credential in Source Code
requirements.txt:1Unpinned Dependencies Installed by Bypassing System Package Protections
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
try:
# 启动爬取任务
response = requests.post(apify_url, params=params, json=payload)
run_data = response.json()
if "error" in run_data:
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
# 检查状态
status_url = f"https://api.apify.com/v2/actor-runs/{run_id}"
status_response = requests.get(status_url, params=params)
status_data = status_response.json()
status = status_data["data"]["status"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
# 获取数据
dataset_url = f"https://api.apify.com/v2/datasets/{dataset_id}/items"
data_response = requests.get(dataset_url, params=params)
data = data_response.json()
print(f"📦 获取到 {len(data)} 条原始数据")
The natural-language instructions and headings are entirely in Chinese, and the document does not indicate that this is a region-specific skill or offer an alternative language option. Per the policy, forcing a specific language without user opt-in can be a natural-language policy violation.
The documentation does not clearly warn users that search queries and scraping targets may be sent to Apify, a third-party service. In an agent context, this can lead to unintentional disclosure of potentially sensitive research terms, business intelligence queries, or user-provided data to an external processor without informed consent.
The invocation examples use very broad natural-language triggers such as asking to scrape Amazon data, without defining explicit activation boundaries or requiring confirmation. In an agent setting, broad triggers can cause accidental invocation, unexpected third-party requests, or data processing based on ambiguous user prompts, especially for a skill that performs scraping and external API use.
The file documents '深度爬取(价格/评分/销量)' as a supported advanced feature and even shows a command-line invocation at L158-L169, while the changelog TODO at L246-L248 says that same feature is not yet implemented. This is an active contradiction in the skill's own documentation about current behavior and capabilities.
L172-L182 describes '定时监控' as an advanced function with a concrete cron example and stated use cases, implying present support. However, L246-L250 lists '定时监控告警' as still TODO, which contradicts the earlier presentation of monitoring capability as available.
The guide tells users to obtain and configure an Apify API key, but it does not clearly disclose that search keywords and scraping activity will be sent to a third-party service. This is a real transparency and privacy issue because users may unknowingly expose business interests, research targets, or usage metadata to Apify.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
配置 cron 每天执行:
# 编辑 crontab
crontab -e
# 添加(每天凌晨 3 点执行)
0 3 * * * cd /path/to/amazon-scraper && python3 amazon_scraper.py
The file-level description and all user-facing messages are written exclusively in Chinese, indicating the skill is designed to operate in a fixed language. There is no option for users to choose a language or any documentation justifying a mandatory Chinese locale, which matches the language/locale policy violation criteria.
The code sends search keywords and target URLs to the external Apify service via HTTP requests, but there is no explicit user warning that input data and scraped context will be transmitted to a third-party platform. Although progress is printed, those messages do not disclose the privacy or external-sharing aspect of the operation.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# 启动 Apify Actor
start_url = f"https://www.amazon.com/s?k={keywords[0].replace(' ', '+')}"
apify_url = "https://api.apify.com/v2/acts/apify~web-scraper/runs"
params = {
"token": APIFY_TOKEN
}
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# 启动 Apify Actor
start_url = f"https://www.amazon.com/s?k={keywords[0].replace(' ', '+')}"
apify_url = "https://api.apify.com/v2/acts/apify~web-scraper/runs"
params = {
"token": APIFY_TOKEN
}
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# 启动 Apify Actor
start_url = f"https://www.amazon.com/s?k={keywords[0].replace(' ', '+')}"
apify_url = "https://api.apify.com/v2/acts/apify~web-scraper/runs"
params = {
"token": APIFY_TOKEN
}
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
try:
# 启动爬取任务
response = requests.post(apify_url, params=params, json=payload)
run_data = response.json()
if "error" in run_data:
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
# 检查状态
status_url = f"https://api.apify.com/v2/actor-runs/{run_id}"
status_response = requests.get(status_url, params=params)
status_data = status_response.json()
status = status_data["data"]["status"]
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
# 获取数据
dataset_url = f"https://api.apify.com/v2/datasets/{dataset_id}/items"
data_response = requests.get(dataset_url, params=params)
data = data_response.json()
print(f"📦 获取到 {len(data)} 条原始数据")
The docstring for generate_report says it returns a整理后的商品列表, but the implementation ends with return unique_products[:max_products] even though max_products is not defined in the function scope. In practice this causes a runtime failure rather than returning the documented processed list, so the documented intent and actual code behavior diverge in a meaningful way.
This markdown file states that the skill scrapes Amazon product data and generates structured reports, including amazon-data.xlsx and amazon-report.md, but it does not warn users that running the skill will write files to the local filesystem. For markdown files, omissions around behaviors that affect user data or system state can warrant a missing-warning finding.
The skill's natural-language instructions and usage guidance are entirely in Chinese, and the file does not state that the skill is intended only for Chinese-speaking users or provide an opt-in language choice. This creates a locale/language policy concern because it effectively forces one language without documented justification.
SQP-3 applies to all file types and includes language or locale policy violations. The file forces a single language for all instructions and examples, with no opt-in, alternate language, or justification for a locale-specific audience.
The dependency is specified with a lower bound only, so builds may resolve to different versions over time and can inadvertently install a vulnerable or untested release. For a security-sensitive supply chain, lack of pinning reduces reproducibility and makes it difficult to verify whether known vulnerable versions are excluded.
openpyxl>=3.0.0
requests>=2.28.0
openpyxl has known historical advisories, and because the manifest does not pin a version, it is impossible to determine from this file whether deployments will use an affected release. The main danger is uncertainty in dependency hygiene: an environment resolver could select a vulnerable version if constraints elsewhere permit it.
Using an unpinned requests dependency means future installs can pull in different versions, including versions later found vulnerable or behaviorally incompatible. This weakens supply-chain control and complicates auditing and incident response.
openpyxl>=3.0.0
requests>=2.28.0