Back to skill

Security audit

Bird Recognition Tool | 鸟类识别工具

Security checks for vulnerabilities and agentic risk

Overview

This skill needs review because it can mix different users’ reports, mishandle service credentials, and upload media despite its advertised non-analysis option.

Prefer waiting for fixes to sender isolation, credential destination checks, export-only handling, and token storage. If evaluating this version, use an isolated single-user workspace, dedicated credentials, and non-sensitive media. Media is uploaded to the LifeEmergence service; do not rely on --export-env-only to prevent uploading. Verify the provider’s retention promises separately. The inspected artifacts support Review, but do not establish intentional malware.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/bird_recognition_analysis.py
Finding

CLI discards upstream sender identity and reuses a workspace-wide account

Content
View full analysis

Impact

In the affected shared-workspace deployment, a second sender can retrieve reports created by the first through the fallback account. New analyses are also attributed to that same account, mixing report ownership.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (24)

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The supplied chunk is a user-account database module, not a bird-recognition or model-training implementation. Although database utilities can support a larger skill, this code specifically manages identities, personal details, and tokens without a visible connection to bird observations or recognition results. These are substantive capabilities not represented by the declared description. No image/video processing, species classification, or custom training is present in this chunk. This assessment is limited to the supplied code; it does not establish that recognition functionality is absent elsewhere.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

Generic utilities and HTTP transport can legitimately support a bird-recognition service; their presence, and the absence of recognition logic in a shared utility file, are not sufficient alone to establish a mismatch. However, this chunk also implements automatic remote account enrollment, persistent identity and token management, and credential forwarding without restricting requests to a bird-recognition endpoint. These are consequential behaviors not represented in the declared purpose. The payment-related text is only returned on an HTTP 402 response; the code does not itself install a payment skill or initiate a payment.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
86% confidence
Finding

The generic AI-analysis endpoints could support bird recognition and are not inherently inconsistent with the description. However, DETAIL_EXPORT_URL explicitly targets /health/order/api/getReportDetailExport?id=, an unrelated health-report resource not disclosed in the declared purpose. This establishes a resource-level mismatch, although the supplied chunk only configures that endpoint and does not demonstrate its use. The advertised species coverage and training support cannot be verified from this configuration-only chunk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
80% confidence
Finding

The supplied code presents itself as a general video-analysis tool and delegates processing to skill.get_output_analysis without any visible bird-recognition configuration or species-specific handling. It also exposes an identity-linked history-listing operation. The advertised training capability and species coverage are not substantiated by this chunk. Because the imported service implementation is not supplied, bird recognition could exist downstream; the mismatch assessment is limited to the interface and behavior visible here.

Content

No source excerpt is available for this finding.

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · SKILL.md (reported line 3)May include surrounding context.

md
---
name: "bird-recognition-analysis"
description: "Identifies bird species in images/videos of target areas. Supports recognition of no less than 500 common bird species, supports customized model training, suitable for ecological observation, garden bird watching and other scenarios. | 鸟类识别工具,识别目标区域图片/视频中的鸟类种类,支持不低于500种常见鸟类识别,支持定制化模型训练,适用于生态观测、庭院观鸟等场景"
version: "1.0.23"
license: "MIT-0"
---

# 🐦 Bird Recognition Tool | 鸟类识别工具

> **智能健康/识别分析中枢** · 图片/视频智能分析

The HTTP helper attaches service credentials to arbitrary absolute destination URLs.

High
Category
Excessive Agency
Confidence
99% confidence
Finding

The wrapper accepts arbitrary absolute HTTP or HTTPS URLs and then supplies service tokens and API keys without checking the destination origin. A caller able to influence the URL can direct credentials to an attacker-controlled server, while HTTP destinations also expose them to network interception.

Content

No source excerpt is available for this finding.

Skill declares no tool scope ('permissions' or 'allowed-tools') but code capabilities were detected: env, file_read, file_write, network, shell.

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

The --export-env-only option promises not to execute analysis, but analysis still runs.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The parser accepts --export-env-only and promises not to perform analysis, but the flag is never checked. With an input supplied, execution still initializes identity and invokes analysis, potentially uploading private backyard imagery despite the caller explicitly selecting a non-analysis operation.

Content

No source excerpt is available for this finding.

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · skills/smyx_analysis/scripts/skill.py (reported line 28)May include surrounding context.

python
result_json = JsonUtil.parse(result_json_pure_text, result_json_pure_text)

        result_json_common_ai_response = result_json.get("commonAiResponse") if isinstance(result_json,
                                                                                           dict) else result_json
        if result_json_common_ai_response:
            result_json = result_json_common_ai_response

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · skills/smyx_analysis/scripts/skill.py (reported line 33)May include surrounding context.

python
result_json = result_json_common_ai_response

        result_json_health_ai_response = result_json.get("healthAiResponse") if isinstance(result_json,
                                                                                           dict) else result_json
        if result_json_health_ai_response:
            result_json = result_json_health_ai_response

Local video content is passed to an analysis API without disclosing the upload to the user.

Medium
Category
Output Handling
Confidence
88% confidence
Finding

The local-file branch reads the entire video into a multipart-style payload and passes it to the analysis API. No prompt, log, or explanatory comment discloses that the video is uploaded; requesting video analysis does not necessarily imply consent to remote processing of potentially private content.

Content

No source excerpt is available for this finding.

The --export-env-only option promises not to perform analysis, but execution still invokes the analysis workflow.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The --export-env-only option is parsed but never consulted before identity initialization and analysis. A caller supplying media while requesting environment export only can therefore initiate unintended remote processing or history retrieval.

Content

No source excerpt is available for this finding.

The skill implements persistent user-profile and credential management unrelated to its declared bird-recognition purpose.

Medium
Category
Excessive Agency
Confidence
93% confidence
Finding

The model supports storing authentication tokens alongside extensive personal information in a workspace SQLite database without application-level encryption or explicit restrictive permissions in this source. This creates a credential and privacy exposure if populated and accessible to another workspace process or reader; bird recognition alone does not justify this broad profile schema, although shared service authentication may explain its presence.

Content

No source excerpt is available for this finding.

FileUtil.open silently truncates existing files without disclosing its destructive behavior.

Medium
Category
Output Handling
Confidence
96% confidence
Finding

Opening a path with mode 'w' immediately truncates any existing file, even before the caller writes content. This generic open helper has no docstring, explanatory comment, confirmation, or operation-specific log warning callers that existing contents will be erased.

Content

No source excerpt is available for this finding.

Recognition requests can silently register a remote user account and persist account credentials.

Medium
Category
Excessive Agency
Confidence
96% confidence
Finding

An ordinary HTTP request can trigger a separate login/registration request with silent=1 and register=1, then persist returned user information and bearer tokens in SQLite. This introduces remote account creation and durable credential storage without an explicit enrollment step, exceeding the expectations established by the bird-recognition description.

Content

No source excerpt is available for this finding.

The HTTP wrapper performs an undisclosed registration/login request using the current user's identity.

Medium
Category
Output Handling
Confidence
96% confidence
Finding

The generic request wrapper can send the current identity as both openId and mobile to a separate login endpoint with registration enabled, without an explicit authorization step. An identity may be a generated pseudonym rather than a phone number, but automatic remote registration still creates an undisclosed privacy-relevant side effect.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
93% confidence
Finding

External transmission alone is expected for a remote recognition service, but this request specifically sends an identity to a separate registration/login service rather than submitting recognition input. The surrounding code can source that identity from API_SECRET_KEY, potentially transmitting a credential as account data as well as causing undisclosed enrollment.

Content

Scanner excerpt · skills/smyx_common/scripts/util.py (reported line 561)May include surrounding context.

python
"source": ConstantEnum.DEFAULT__SKILL_HUB_NAME
            }
            try:
                _response = requests.post(_url, json=_data)
                if _response.status_code == 200:
                    _response_json = _response.json()
                    if _response_json and _response_json.get("success"):

The automatic history-query trigger includes the generic phrase “历史报告” (“historical reports”) without requiring bird-recognition context.

Low
Category
Trigger Abuse
Confidence
90% confidence
Finding

The examples include the generic trigger “历史报告,” while the instructions require automatic cloud retrieval and display of account-linked reports. This can cause an unrelated historical-report request to trigger bird-report access without the user intending that operation.

Content

No source excerpt is available for this finding.

Configuration loading silently creates directories and writes missing configuration files.

Low
Category
Output Handling
Confidence
95% confidence
Finding

YamlUtil.load creates parent directories and writes a YAML file when the requested path does not exist, without a comment, docstring, log, or confirmation disclosing this side effect. Because BaseEnum.init_subclass invokes this loader at L053 and L058, importing the module can modify the filesystem even though the operation appears to be configuration loading.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · skills/smyx_common/scripts/dao.py (reported line 243)May include surrounding context.

python
username = getattr(model, "username", None)
            if username:
                column_names = self.__model__.__table__.columns.keys()
                update_data = {key: getattr(model, key) for key in column_names if key != "username"}
                return self.update_by_username(username, **update_data)

            return None

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · skills/smyx_common/scripts/dao.py (reported line 326)May include surrounding context.

python
if filters:
                for key, value in filters.items():
                    query = query.filter(getattr(self.__model__, key) == value)

            if offset:
                query = query.offset(offset)

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · skills/smyx_common/scripts/dao.py (reported line 441)May include surrounding context.

python
if filters:
                for key, value in filters.items():
                    query = query.filter(getattr(self.__model__, key) == value)

            return query.scalar()
        finally:

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · skills/smyx_common/scripts/dao.py (reported line 353)May include surrounding context.

python
column_names = self.__model__.__table__.columns.keys()

            for key in column_names:
                value = getattr(model, key)
                setattr(instance, key, value)

            session.commit()

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · skills/smyx_common/scripts/util.py (reported line 30)May include surrounding context.

python
elif isinstance(cur, dict):
                        cur = cur.get(part, default)
                    else:
                        cur = getattr(cur, part)
                return cur
            except Exception:
                return default