T09 · Insecure Skill Coding Practices
- Location
SKILL.md:39- Finding
API Key Exposure Through Command-Line Arguments
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears to do the advertised Mysteel steel bid and supply-demand lookups, but it stores an API key in a plaintext project file and documents passing that key on the command line.
Install only if you are comfortable giving the skill a Mysteel API key and sending steel-market queries to Mysteel. Prefer not to use the documented --save_api_key command with a real key unless you can protect shell history and the workspace; if you do use it, keep references/api_key.md out of source control and shared archives, restrict file access, and rotate the key if it may have been exposed.
SKILL.md:39API Key Exposure Through Command-Line Arguments
scripts/bidding_api.py:65Plaintext API Key Stored Without Enforced File Permissions in Bidding Script
scripts/supply_demand_api.py:62Plaintext API Key Stored Without Enforced File Permissions in Supply-Demand Script
该代码块的核心行为非常明确:它通过 token 调用 https://mcp.mysteel.com/mcp/info/vector/rag-search 接口,参数固定 innerType=18,执行招投标数据的自然语言检索,并带有近 3 个自然年的时间限制。虽然这与声明中的“查询招投标信息或发现项目机会”部分一致,但声明还包含“支持钢材供需现货信息查询”“找采购方”“找供应方”等更广泛能力,而代码中没有任何对应实现,也没有其他数据源、接口、查询分支或资源访问来支持这些功能。因此描述对技能能力有明显扩张,构成描述与实际行为不匹配。
该描述与代码存在实质性不一致。代码的核心功能明确聚焦于‘钢材供需现货信息查询’,通过 querySupplyDemandSpot 接口获取供应/求购信息,能够支持“找采购方/找供应方”这一部分声明。但声明还包含‘招投标数据检索’及‘发现项目机会’,而提供的代码中没有任何相关 API、参数、数据结构或处理逻辑。因此,技能描述比实际能力更宽,构成能力层面的描述-行为不匹配。API Key 的本地读写属于支撑性实现细节,不是主要 mismatch 原因。
The skill declares executable scripts that perform network access and local file read/write, but it does not declare any tool scope such as permissions or allowed-tools. This creates an authorization transparency gap: an agent or reviewer cannot easily constrain or understand what the skill may access, increasing the chance of over-privileged execution or unintended credential/file handling.
The activation description is broad enough to match common business queries such as buying, selling, procurement, or project discovery. Over-broad triggering can cause the agent to invoke networked and file-capable code in contexts the user did not intend, leading to unnecessary data disclosure, credential use, or external requests.
The skill instructs users to save an API key locally in references/api_key.md without warning about credential persistence or describing protection measures. Storing secrets in a plain local file, especially in a predictable repository path, increases the risk of accidental disclosure through file reads, commits, backups, or workspace sharing.
SQP-3 applies to all file types and includes language or locale policy violations. The title and the full document content require Chinese interaction but do not mention that the skill is China-region-specific or provide any user language choice.
L138-L142 写明当表达模糊时“通过上下文和关键词进行智能判断,不直接询问用户”,仅在过于模糊时可提供选项;但后文示例对“钢材资源”这一模糊表达直接要求补充询问用户。该文档内部对同类场景给出了相互冲突的执行意图,可能导致技能行为与预期不一致。
This Python file's docstring, CLI help text, and runtime messages are written entirely in Chinese, which imposes a specific language on users. The file does not offer any language/locale selection or explain that the skill is intentionally region-specific, so it conflicts with the policy against forcing a language without user opt-in.
The script persists the API token to a local file under references/api_key.md, which creates an unnecessary credential-at-rest risk for a retrieval skill. If the workspace, repo, logs, backups, or packaging process expose that file, the token can be reused to access the upstream bidding API.
The disk-write path for saving API credentials is broader than the stated purpose of query-only bidding lookup and increases the attack surface. A user or calling system can cause sensitive credentials to be written to disk, where they may later be disclosed through source control, artifact collection, shared environments, or local compromise.
The top-level documentation states the file is for supply/demand spot queries, but the implementation also manages API keys. This mismatch is security-relevant because operators may review or approve the skill assuming it only performs data retrieval, not local credential storage.
The script includes functionality to persist an API key to disk even though the skill is described as a query/search tool. That expands its privilege and data-handling behavior beyond user-visible expectations, which can lead to accidental credential storage on shared hosts or in improperly protected workspaces.
The code writes the API key into references/api_key.md without any warning, confirmation, or permission hardening. Storing a live credential in a plain text markdown file increases the chance of leakage through backups, source-control mistakes, shared directories, or other local users.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# 4. 发起请求
try:
response = requests.post(url, headers=headers, json=payload, timeout=30)
if response.status_code >= 400:
raise Exception(f"HTTP请求失败: 状态码 {response.status_code}, 响应内容: {response.text}")
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# 4. 发起请求
try:
response = requests.post(url, headers=headers, json=payload, timeout=30)
if response.status_code >= 400:
raise Exception(f"HTTP请求失败: 状态码 {response.status_code}, 响应内容: {response.text}")
All user-facing natural-language text in the script, including the module description, CLI help, and error messages, is exclusively in Chinese. This imposes a language choice on users without opt-in or an alternative locale, which matches the stated language/locale policy concern.
No suspicious patterns detected.