Back to skill

Security audit

FitBuddy

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a coherent fitness tracker, but it contains unsafe local file handling and risky authorization/setup guidance that users should review before installing.

Review this skill before installing. It stores sensitive fitness and health information locally, can create persistent reminders through OpenClaw, and may send reminder content through configured messaging channels. Avoid the documented approve --latest device approval flow; verify the exact device identity instead. Do not pass untrusted dates or output paths to the scripts, and prefer pinned, isolated dependency installs.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/record.py:23
Finding

Path Traversal in Record Date Parameters Enables JSON File Access Outside the Records Directory

Content
View full analysis

Vulnerability Details

File Location: scripts/record.py:23-52, with affected command-line parameters at scripts/record.py:831-887
Vulnerability Type: Path traversal and unrestricted file access
Risk Level: High

Vulnerable Code

python
def load_day(date_str):
    path = os.path.join(RECORDS_DIR, f"{date_str}.json")
    if os.path.exists(path):
        with open(path, "r", encoding="utf-8") as f:
            return json.load(f)
    return {
        "date": date_str,
        "weight_kg": None,
        "meals": {"breakfast": [], "lunch": [], "dinner": [], "snack": []},
        "water_ml": 0,
        "water_target_ml": 2000,
        "exercises": [],
        "daily_summary": {
            "total_calories_in": 0,
            "total_calories_out": 0,
            "total_protein_g": 0,
            "total_carbs_g": 0,
            "total_fat_g": 0,
            "total_water_ml": 0,
        },
    }


def save_day(record):
    os.makedirs(RECORDS_DIR, exist_ok=True)
    path = os.path.join(RECORDS_DIR, f"{record['date']}.json")
    recalc_summary(record)
    with open(path, "w", encoding="utf-8") as f:
        json.dump(record, f, ensure_ascii=False, indent=2)
    return record

Representative affected argument definitions:

python
p_w.add_argument("--date", required=True)
p_m.add_argument("--date", required=True)
p_wa.add_argument("--date", required=True)
p_e.add_argument("--date", required=True)
p_u.add_argument("--date", required=True)
p_t.add_argument("--date", required=True)
p_a.add_argument("--date", required=True)

A similar construction exists in scripts/chart.py:149:

python
path = os.path.join(RECORDS_DIR, f"{date_str}.json")

Technical Analysis

The --date value is accepted as an unrestricted string and interpolated directly into a filesystem path. os.path.join() does not remove parent-directory components such as ...[truncated 1633 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse every date before any filesystem operation:

    python
    from datetime import datetime
    
    def validate_date(value):
        parsed = datetime.strptime(value, "%Y-%m-%d")
        canonical = parsed.strftime("%Y-%m-%d")
        if value != canonical:
            raise ValueError("Date must use canonical YYYY-MM-DD format")
        return canonical
    
  2. Resolve the final path and enforce containment:

    python
    def record_path(date_str):
        safe_date = validate_date(date_str)
        base = os.path.realpath(RECORDS_DIR)
        path = os.path.realpath(os.path.join(base, safe_date + ".json"))
        if os.path.commonpath([base, path]) != base:
            raise ValueError("Record path escapes the records directory")
        return path
    
  3. Use this single path-construction function in load_day(), save_day(), reporting functions, and chart functions.

  4. Add parser-level validation with an argparse type function so malformed values are rejected before command dispatch.

  5. Write records atomically through a temporary file inside RECORDS_DIR, then replace the destination.

  6. Add regression tests for ../, absolute paths, alternate separators, malformed dates, and canonical valid dates.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
references/channels.md:64
Finding

Approval of the Latest Pending Device Can Grant Write Access to an Unverified Device

Content
View full analysis

Vulnerability Details

File Location: references/channels.md:64-74
Vulnerability Type: Unsafe device authorization and privilege escalation guidance
Risk Level: High

Vulnerable Code

bash
openclaw devices list
openclaw devices approve --latest

The documented process uses the approval command when an agent lacks operator.write permission and then retries the state-changing cron operation.

Technical Analysis

The --latest selector authorizes a request based on ordering rather than a verified device identifier or fingerprint. There is no documented requirement to confirm that the latest request belongs to the intended agent.

Device pairing is an access-control boundary. Approving an unverified pending device may grant it write-capable operator permissions, allowing it to perform state-changing Gateway operations. Although this command is presented as manual troubleshooting guidance rather than being executed automatically by the Python scripts, following the guidance can still weaken authorization security.

Attack Path

  1. An attacker submits a device pairing request near the time the user is troubleshooting reminder creation.
  2. The attacker ensures that their request is the most recent pending request.
  3. The user follows the documentation and runs openclaw devices approve --latest.
  4. The command approves the attacker's request rather than the intended agent.
  5. The newly authorized device obtains the permissions assigned by the approval flow, potentially including operator.write.
  6. The attacker uses those permissions to perform available state-changing Gateway operations.

Impact Assessment

The affected authorization boundary is the OpenClaw Gateway device-pairing system. A successfully approved attacker-controlled device could obtain write capabilities and modify resources exposed to operators, including scheduled tasks and related Gateway-managed state. The exact s ...[truncated 180 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the recommendation to use --latest for security-sensitive approval.
  2. Require the user to list pending requests and inspect each device's unique identifier, fingerprint, origin, and requested permissions.
  3. Approve only a specific verified device ID, using the exact-ID form supported by OpenClaw.
  4. Require an out-of-band comparison of the pairing code or fingerprint before approval.
  5. Display the permissions being granted and request explicit user confirmation.
  6. Grant only the minimum permission necessary for reminder management rather than broad write access when finer-grained permissions are available.
  7. Document how to revoke an accidentally approved device and review recent authorization events.

T08 · Insecure Dependencies

Warning
Location
README.md:158
Finding

Unpinned Global Installation of the mcporter npm Package Creates Supply-Chain Exposure

Content
View full analysis

Vulnerability Details

File Location: README.md:158-162, also repeated in references/channels.md:18-23 and references/mcd-integration.md:27-40
Vulnerability Type: Unpinned global third-party dependency installation
Risk Level: Medium

Vulnerable Code

bash
npm install -g mcporter
mcporter config add mcd-mcp "https://mcp.mcd.cn" --header "Authorization=Bearer YOUR_TOKEN"

Technical Analysis

The installation command requests the latest package version available under the mcporter package name. It does not specify a reviewed version, lockfile, integrity hash, or isolated installation location.

npm package installation can execute lifecycle scripts. A global installation also places package executables into the user's global npm environment, increasing the scope of changes compared with a project-local, locked dependency.

No evidence in the audited project shows that the current mcporter package is malicious. The confirmed issue is the unsafe and non-reproducible dependency installation practice, which makes the effective installed code dependent on mutable upstream registry state.

Attack Path

  1. The upstream npm package, maintainer account, publication pipeline, or a future release is compromised.
  2. A user follows the project documentation and runs the unpinned global installation command.
  3. npm resolves the package name to the compromised current release.
  4. Package installation or lifecycle scripts execute with the privileges of the invoking user.
  5. The installed global executable can subsequently access MCP configuration and authorization tokens supplied during setup.

Impact Assessment

A compromised dependency could execute code with the installing user's privileges, modify user-accessible files, alter globally installed npm commands, or access secrets available to its process. The issue does not establish that compromise has occurred; it creates a supply-chain path ...[truncated 68 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin mcporter to a specifically reviewed version rather than installing the latest release.
  2. Verify the package publisher, repository, signatures or provenance, and package integrity before recommending installation.
  3. Prefer a project-local installation with a committed lockfile over npm install -g.
  4. Use npm ci with a reviewed lockfile in an isolated directory where practical.
  5. Disable lifecycle scripts during installation when they are not required, then explicitly review any necessary scripts.
  6. Document the expected package checksum or integrity value and provide a controlled update process.
  7. Keep authorization tokens out of shell history where possible and store them through a dedicated secret-management mechanism with restrictive permissions.

T08 · Insecure Dependencies

Warning
Location
README.md:188
Finding

Unpinned matplotlib Installation Produces Non-Reproducible Dependency Resolution

Content
View full analysis

Vulnerability Details

File Location: README.md:188-192
Vulnerability Type: Unpinned Python dependency installation
Risk Level: Medium

Vulnerable Code

text
Requirements:
- Python 3.8+
- matplotlib — for chart generation (`pip install matplotlib`)
- OpenClaw — for cron-based reminders

The executable installation instruction is:

bash
pip install matplotlib

Technical Analysis

The command installs whichever matplotlib release and transitive dependencies are selected by the package index at installation time. The project does not provide an exact version, constraints file, lockfile, or package hashes.

This prevents reproducible installation and leaves dependency selection dependent on mutable package-index state. Python installations can execute build-system code for source distributions, and imported dependencies execute Python module initialization code.

No evidence in the audited project demonstrates that the current official matplotlib package is malicious. The finding concerns the lack of version and integrity controls.

Attack Path

  1. An upstream package account, release artifact, build pipeline, package index, or transitive dependency is compromised.
  2. A user runs the documented unpinned installation command.
  3. pip resolves and downloads the compromised artifact selected at that time.
  4. Build or installation code executes, or malicious code runs when chart.py imports the dependency.
  5. The code operates with the privileges and data access of the user running the chart functionality.

Impact Assessment

A compromised resolved dependency could execute code under the invoking user's account and access user-readable fitness records, profile data, and other files available to the process. The finding represents supply-chain exposure rather than evidence of an existing malicious package.

Remediation
View remediation

Remediation Suggestions

  1. Add an exact, reviewed matplotlib version to a dependency manifest.
  2. Lock all transitive dependencies using a reproducible dependency-management tool.
  3. Use pip hash checking, such as a requirements file containing --hash entries and installation with --require-hashes.
  4. Install dependencies in a dedicated virtual environment rather than the user's global Python environment.
  5. Prefer trusted binary wheels and review any build requirements before allowing source builds.
  6. Add automated dependency scanning and a controlled process for reviewing and updating pinned versions.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (35)

Harmful Content Injection

Critical
Category
Prompt Injection
Confidence
90% confidence
Finding

This content may contain harmful instructions that could cause physical harm if followed. CRITICAL: Review carefully before use.

Content

Scanner excerpt · fitbuddy-data/i18n.json (reported line 43)May include surrounding context.

json
"carbs_low": "Still room for carbs",
      "fat_full": "Fats almost at limit, choose low-fat options",
      "fat_low": "Still room for fats",
      "rest_day": "Rest day — eat well and recover~",
      "train_day": "Training day — fuel up on carbs for energy!",
      "calories_low": "Plenty of calories left, don't starve yourself!"
    },
    "record_template": "✅ Recorded: {food} ({calories} kcal)\n📊 Daily: {consumed}/{target} kcal\n   Protein {protein}/{protein_target}g | Carbs {carbs}/{carbs_target}g | Fat {fat}/{fat_target}g\n💡 {suggestion}",
    "food_added": "Added to food database!",
    "food_not_found": "{food} not found in database, let me estimate~",
    "water_done": "Water goal reached today, awesome! 💧"

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill advertises broad health-tracking, nutrition, reminder, and planning behavior, but the described implementation relies on local scripts/files and appears not to provide the claimed end-user features in a verifiable way. This mismatch can mislead users and systems into granting trust or permissions under false assumptions, which is especially concerning in a health context where users may act on incomplete or missing functionality.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The initialization trigger is described as responding to broadly fitness-related statements, which can cause the skill to activate on ordinary conversation rather than clear user intent. In a health-tracking context, this increases the chance of collecting sensitive profile data or starting setup flows without sufficiently explicit consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README states the skill asks for health-related profile data such as height, weight, age, gender, goals, and diet preferences, but it does not clearly warn users that this data will be stored locally in profile and record files. Because this is sensitive health and lifestyle information, missing transparency around storage, retention, and access can expose users to privacy harm if the environment is shared or compromised.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill instructs the agent to read and write local files and execute shell-based scripts, but it does not declare any explicit tool scope or permissions boundary. This creates an undeclared capability surface where an orchestrator or reviewer cannot reliably constrain what the skill may access, increasing the risk of unintended file access, data modification, or command execution.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger conditions are broad enough to match ordinary fitness or diet conversation, so the skill may activate in situations where the user did not intend persistent logging, profile modification, or tool use. In this skill, that is more dangerous because activation can lead to reading and writing health-related records and directly editing profile data.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The guide tells users that health information 'only stays on the local device' but later instructs configuring reminder channels, creating cron tasks, and sending test messages. That creates a misleading privacy assurance around highly sensitive health data; if reminders or channel payloads include profile-derived content, data may leave the device or be exposed through third-party messaging systems.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill collects and persists sensitive health conditions, pregnancy status, medication use, allergies, and dietary habits into profile.json, but the save step does not prominently warn the user about the sensitivity, retention, or access implications. In a fitness/nutrition skill, this is especially risky because the dataset contains medical-adjacent personal information that could be exposed to other local users, backups, logs, or integrated tooling.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The McDonald's-specific promo notifications and coupon auto-claim features extend the skill beyond fitness tracking into restaurant marketing and transactional facilitation. Even though both are marked OFF by default, embedding these capabilities in the skill creates scope creep, increases commercial influence risk, and can steer users toward vendor-specific consumption unrelated to the assistant’s stated health purpose.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Scheduled campaign and coupon checking introduces persistent marketing-monitoring behavior that is not necessary for calorie logging, nutrition lookup, or training support. In a fitness assistant context, this is more dangerous because it creates an ongoing commercial engagement channel that can nudge user behavior toward a specific restaurant under the guise of diet support.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The guide gives quantitative nutrition advice and explicitly says high protein intake is 'completely safe' for healthy people, while only briefly excluding kidney disease and providing no general medical disclaimer or advice to seek professional guidance. In a fitness-tracking skill, users may treat this as personalized health advice and follow it despite undisclosed conditions, which can lead to inappropriate dietary decisions or delayed medical consultation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The instruction requires the assistant to output only in a specific style and language context (Chinese, with a fixed persona/tone: '语气:爱弥斯') without indicating user choice or opt-in. This is a natural-language policy concern because it imposes a locale/style constraint globally rather than offering the user a language preference.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

L32 将触发条件写为“用户说"看看这周报告"/"周报"时生成”,其中“周报”单独作为触发短语过于简短且常见,缺少上下文约束,容易与普通对话或其他报表需求混淆。该描述也没有提供排除条件或更明确的触发范围。

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This section gives exercise programming and progressive overload guidance for compound lifts like squats and deadlifts, plus intensity escalation rules, without clear safety warnings, screening boundaries, or advice to stop and seek qualified medical help when pain/injury risk is present. In a fitness coaching skill, that omission is materially risky because users may follow the guidance as personalized instruction despite limited assessment, increasing the chance of musculoskeletal injury or unsafe training progression.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code declares the skill as Chinese-language and consistently emits Chinese text in chart titles, labels, and error messages, but provides no option for the user to select another language or locale. That creates a natural-language policy concern because the skill effectively enforces a specific language without opt-in or justification.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The command accepts a user-controlled --output path and passes it directly to fig.savefig(), allowing writes to arbitrary filesystem locations accessible to the process. In an agent/skill context, this exceeds the fitness-charting purpose and can overwrite files, drop artifacts in sensitive locations, or assist in chained attacks if an attacker can influence arguments.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This chart command has the same arbitrary file-write primitive via the --output argument, with no validation of destination path. Even though the content written is just an image, arbitrary write access can still overwrite existing files the process can reach or place attacker-chosen files outside the application data area.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The macro pie chart command also writes to args.output without checking whether the target path is appropriate for this skill. In a multi-tool or agent environment, arbitrary path writes are dangerous because they can be abused beyond the intended chart-generation capability and may impact integrity of local files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script persists a fitness profile containing sensitive personal and health-related data, including age, weight, goals, reminders, and channel configuration, to a local JSON file without any notice, consent flow, retention policy, or access controls. In the context of a fitness/diet assistant, this increases privacy risk because users may not realize their health data is being stored on disk where other local users, backups, or processes could access it.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script persistently stores sensitive health data such as weight, diet, exercise, and water intake in local JSON files without any disclosure, consent, retention policy, or access controls. Even if this is intended functionality, undisclosed persistence of health-related data increases privacy risk, especially on shared systems or agent environments where users may not expect local storage.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script builds and stores derived behavioral profiles (food_frequency, meal_combinations) from user eating history without user-facing notice or opt-in. Profiling based on health and diet behavior is more sensitive than raw logging because it creates inferred habits that can reveal routines, preferences, and potentially medical or lifestyle information.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The manifest describes a fitness and diet logging assistant with calculations and progress display, but this file's progress command invokes an external script using subprocess.run. Launching subprocesses is a stronger execution capability than simple local record keeping or data calculation, and is not justified by the manifest text for this specific skill file.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/record.py (reported line 691)May include surrounding context.

python
# 从 calc.py 获取当天实际目标(低碳/高碳)
    import subprocess
    try:
        result = subprocess.run(
            [sys.executable, os.path.join(SCRIPT_DIR, "calc.py"), "daily",
             "--profile", PROFILE_PATH, "--date", args.date],
            capture_output=True, text=True, encoding="utf-8")

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The README says reminders are automatically created during initialization, but it does not clearly warn users that persistent scheduled notifications will continue until changed or removed. This can lead to unexpected ongoing prompts, possible disclosure of health-related routines via device notifications, and user confusion about how to disable them.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The file presents core trigger phrases and operational guidance primarily in Chinese while also including English activation text, but it does not state whether the user may choose their preferred language. This can amount to a language-policy issue because the skill behavior appears biased toward a specific language without explicit user opt-in or justification.

Content

No source excerpt is available for this finding.