Back to skill

Security audit

Fish Aquatic Pet Health Diagnosis Analysis Tool | 鱼类水族宠物健康诊断分析工具

Security checks for vulnerabilities and agentic risk

Overview

Review is needed because the skill can upload videos despite an export-only setting and does not adequately explain remote account creation or stored credentials.

Prefer a corrected release that honors export-only mode and clearly explains account registration, credential storage, and account isolation. Uploads go to LifeEmergence; use non-sensitive footage and a separate workspace. Material gaps in the partial scanner report were independently investigated, but server retention and account isolation remain unverified. The artifacts support Review rather than a malicious verdict.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
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
94% confidence
Finding

The video-analysis commands and report-formatting options match the declared purpose. However, historical-report retrieval is an additional capability not disclosed in the description, and its documented trigger phrases extend activation beyond requests to analyze a supplied video. The module implementation is not provided, so server-side API calls and diagnostic behavior cannot be independently verified from this chunk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The supplied chunk is a user-account persistence layer, not an aquatic-pet video-analysis implementation. It contains no video ingestion, health API requests, feature analysis, disease identification, or report generation. Database infrastructure can be a supporting implementation detail, but this chunk specifically manages personal profiles and credentials without any visible connection to the declared analysis workflow. That constitutes an undeclared capability in the supplied code. No network transmission or token exfiltration is shown, and the assessment does not establish what other skill files implement.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

The visible command targets a differently named analysis domain and requests a listing, which does not match the declared aquatic pet video diagnosis purpose. The module implementation is not supplied, so its underlying behavior and any resource access cannot be verified.

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: "aquarium-analysis"
description: "When a user provides a video URL or file of aquatic pets such as goldfish, koi, betta, shrimp, crab, etc. for analysis, this skill is triggered to perform aquatic pet health diagnosis analysis. Supports uploading local videos or online video URLs, calls server-side API for aquatic pet health examination, analyzes features such as scales, fins, body color, activity level, identifies potential diseases and outputs a pet health report. | 鱼类水族宠物健康诊断分析工具,当用户提供金鱼、锦鲤、斗鱼、虾、蟹等水族宠物的视频 URL 或文件需要分析�

Incomplete referenced artifact analysis

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| 🐍 必要脚本 | [`scripts/aquarium_analysis.py`](scripts/aquarium_analysis.py) | 调用 API、执行分析或查询历史报告 | 执行分析或查询时使用 |

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.

Generic history-report phrases can trigger aquarium report retrieval outside the intended domain.

Medium
Category
Trigger Abuse
Confidence
94% confidence
Finding

The automatic trigger list includes “查询历史报告” (query historical reports) without requiring aquarium or fish-health context. Line 189 further includes “历史报告” (historical reports) as an automatic trigger, so requests about unrelated reports could invoke this skill.

Content

No source excerpt is available for this finding.

The documented export-only mode does not prevent video analysis.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The help text for --export-env-only explicitly promises to output environment-setting commands without performing analysis. However, args.export_env_only is never checked, so supplying this flag alongside --input or --url still reaches analyze_video at L215-L223 and delegates to the analysis backend at L60, contrary to the user's explicit no-analysis selection.

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 contents are submitted to an analysis API without disclosure of the upload.

Medium
Category
Output Handling
Confidence
90% confidence
Finding

The code reads the entire local file, constructs a file-upload payload, and passes it to the analysis API. No prompt, log, or explanatory comment discloses that the user's video leaves the local system; the comment only describes reading the file.

Content

No source excerpt is available for this finding.

The --export-env-only option promises not to execute analysis, but the code ignores it and proceeds with video analysis.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The option's help text explicitly promises to output environment-variable export commands without performing analysis. However, args.export_env_only is never checked: when a video input is supplied, execution reaches analyze_video at L89-L95 and skill.get_output_analysis at L37, potentially submitting the video for server-side analysis despite the user's explicit no-analysis selection.

Content

No source excerpt is available for this finding.

Implements persistent user-profile management beyond aquatic-pet video analysis.

Medium
Category
Excessive Agency
Confidence
86% confidence
Finding

The User model stores real names, email addresses, birthdays, sex, age, and authentication tokens (L448–L465), and UserDao exposes inherited CRUD operations for those records (L470–L472). This provides persistent personal-profile management in a workspace-shared database (L95–L97, L174–L180), a capability not justified by the stated video-upload, server-side examination, and health-report workflow; API authentication alone does not explain the broader demographic profile.

Content

No source excerpt is available for this finding.

ai_chat documents invoking an analysis agent, but agent execution is disabled and the method returns no analysis.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The docstring states that this method invokes openclaw agent through subprocess and returns an analysis result or session ID. However, the command and subprocess call are commented out; the method instead assigns an empty dictionary to result, accesses its nonexistent stderr attribute, and catches the resulting exception without returning a result. This contradicts the documented analysis behavior rather than merely changing an implementation detail.

Content

No source excerpt is available for this finding.

FileUtil.open silently truncates existing files without disclosing its write-only behavior.

Medium
Category
Output Handling
Confidence
97% confidence
Finding

Opening a path with mode 'w' immediately truncates an existing file, even before the caller writes anything. This generically named helper has no docstring, comment, confirmation, or action log explaining that destructive behavior; exception tracing does not disclose successful truncation.

Content

No source excerpt is available for this finding.

API requests can silently register a remote user account, extending the skill beyond its declared video-analysis purpose.

Medium
Category
Excessive Agency
Confidence
88% confidence
Finding

The authentication helper posts to /sys/phoneLogin with both silent=1 and register=1. When tokens are unavailable, the request wrapper invokes this helper (L589-L590) and persists returned account information and tokens locally (L595-L604), introducing automatic account provisioning rather than merely authenticating an existing account for aquatic-pet analysis.

Content

No source excerpt is available for this finding.

HTTP authentication silently transmits the current identity and requests remote registration.

Medium
Category
Output Handling
Confidence
92% confidence
Finding

The authentication helper posts the current username as both openId and mobile to a separate login endpoint with registration enabled. This automatic side effect of an ordinary HTTP request has no explanatory comment, docstring, confirmation, or user-facing action log disclosing the identity transmission and possible account creation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

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"):

Loading configuration silently creates directories and files when the configuration is missing.

Low
Category
Output Handling
Confidence
90% confidence
Finding

YamlUtil.load creates parent directories and writes a YAML file without a prompt, log, docstring, or explanatory comment. Because BaseEnum.init_subclass invokes this loader at L053 and L058, importing the module can cause filesystem changes that callers would not ordinarily expect from loading configuration.

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 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/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/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