Back to skill

Security audit

Personal Health Agent

Security checks for vulnerabilities and agentic risk

Overview

This Fitbit health skill is mostly coherent, but it exposes sensitive health data and stored tokens to unrestricted Python execution and stores credentials in plaintext without clear safeguards.

Review carefully before installing. Use only if you are comfortable storing Fitbit credentials, OAuth tokens, synced health records, and optional health-condition notes in local plaintext files, and avoid using the custom Python analysis feature unless you fully trust the exact code being executed. Prefer a version that uses secure secret storage, owner-only file permissions, explicit confirmations for health-data access, and fixed analysis commands instead of unrestricted exec.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fitbit_setup.py:53
Finding

Sensitive credentials, OAuth tokens, and health records are stored without restrictive file permissions

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/fitbit_analyze.py:159
Finding

Unrestricted agent-directed Python execution exposes health data and host process privileges

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
Findings (41)

Tainted flow: 'CLIENT_ID' from os.getenv (line 24, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fitbit_auth.py (reported line 65)May include surrounding context.

python
def exchange_code(code: str) -> dict:
    """Exchange authorization code for tokens."""
    resp = httpx.post(
        TOKEN_URL,
        data={
            "client_id": CLIENT_ID,

Tainted flow: 'CLIENT_ID' from os.getenv (line 24, credential/environment) → httpx.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/fitbit_auth.py (reported line 82)May include surrounding context.

python
def refresh_token(token_data: dict) -> dict:
    """Refresh an expired access token."""
    resp = httpx.post(
        TOKEN_URL,
        data={
            "grant_type": "refresh_token",

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 27)May include surrounding context.

  1. Save credentials:
    bash
    cd ~/.openclaw/workspace/skills/personal-health-agent
    cp .env.example .env
    # Edit .env with your Client ID and Secret
    

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 28)May include surrounding context.

bash
   cd ~/.openclaw/workspace/skills/personal-health-agent
   cp .env.example .env
   # Edit .env with your Client ID and Secret
  1. Authorize: Tell your OpenClaw agent /health_setup and follow the prompts.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fitbit_auth.py (reported line 113)May include surrounding context.

python
```bash
   cd ~/.openclaw/workspace/skills/personal-health-agent
   cp .env.example .env
   # Edit .env with your Client ID and Secret
   ```

3. **Authorize:** Tell your OpenClaw agent `/health_setup` and follow the prompts.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fitbit_setup.py (reported line 40)May include surrounding context.

python
```bash
   cd ~/.openclaw/workspace/skills/personal-health-agent
   cp .env.example .env
   # Edit .env with your Client ID and Secret
   ```

3. **Authorize:** Tell your OpenClaw agent `/health_setup` and follow the prompts.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill handles Fitbit client credentials, OAuth callback data, and detailed health telemetry, but the description and setup flow do not provide clear privacy, retention, or handling warnings at the point of collection. Given the sensitivity of both health data and authentication artifacts, users may disclose secrets without understanding storage, logging, and exposure risks.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill instructs the agent to ask the user to paste the Fitbit Client ID, Client Secret, and the full OAuth callback URL directly into conversation, then reuse them in shell commands. This exposes sensitive credentials and authorization artifacts to chat logs, prompt history, and potentially other tools or operators, creating a straightforward path to account compromise and unauthorized access to health data.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill explicitly instructs the agent to execute arbitrary Python supplied as a string via fitbit_analyze.py, which creates a broad code-execution surface beyond normal health analytics. If a user or downstream prompt can influence that code, it could read local files, exfiltrate health data or secrets, or perform unintended system actions under the agent's privileges.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

Although the skill is presented as a Fitbit health analysis assistant, it exposes a general arbitrary Python execution surface over personal health data. The mismatch in expected capability increases the chance that users or downstream agents will pass untrusted prompts/code, leading to full compromise of confidentiality and integrity within the local execution context.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code executes arbitrary Python without any confirmation prompt, trust check, or warning at the point of execution, despite exposing sensitive Fitbit and profile data in the namespace. In this health-assistant context, silent execution materially raises the chance of unnoticed exfiltration or destructive actions because users may expect benign data analysis rather than unrestricted code execution.

Content

No source excerpt is available for this finding.

exec() call detected

High
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

The script directly executes attacker-controlled Python via exec(code, namespace) with full Python semantics and access to imported modules, filesystem paths, and sensitive Fitbit/profile data. This enables arbitrary code execution, local file access, data exfiltration, and potentially shell command execution through Python's standard capabilities.

Content

Scanner excerpt · scripts/fitbit_analyze.py (reported line 199)May include surrounding context.

python
stdout = io.StringIO()
    try:
        with contextlib.redirect_stdout(stdout):
            exec(code, namespace)
        output = stdout.getvalue()
        if output:
            print(output)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fitbit_auth.py (reported line 81)May include surrounding context.

python
def refresh_token(token_data: dict) -> dict:
    """Refresh an expired access token."""
    resp = httpx.post(
        TOKEN_URL,
        data={

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fitbit_auth.py (reported line 113)May include surrounding context.

python
def main():
    if not CLIENT_ID or not CLIENT_SECRET:
        print("ERROR: Set FITBIT_CLIENT_ID and FITBIT_CLIENT_SECRET in .env")
        print(f"  .env location: {BASE_DIR / '.env'}")
        sys.exit(1)

    # Non-interactive: exchange a redirect URL

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 · scripts/fitbit_insights.py (reported line 113)May include surrounding context.

python
ng_hr"].mean()
            std = hr_valid["resting_hr"].std()
            if std > 0:
                recent = hr_valid.tail(3)
                for _, row in recent.iterrows():
                    z = (row["resting_hr"] - mean) / std
                    if z > 2:
                        insights.append(make_insight(
                            "anomaly", "high",
                            "❤️‍🔥 Elevated resting heart rate",
                            f"On {row['date'].strftime('%b %d')}, your resting HR was {row['resting_hr']:.0f} bpm — "
                            f"above your baseline of {mean:.0f} bpm. Could indicate stress, poor sleep, illness, or dehydration.",
                            {"date": str(row["date"].date()), "resting_hr": round(row["resting_hr"]),
                             "avg_hr": round(mean), "z_score": round(z, 2)},
                            "Monitor over the next few days. If consistently elevated, consider: Are you stressed? Getting enough sl

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

This code path saves Fitbit client credentials into plaintext .env storage, creating a credential exposure risk if the repository, filesystem, backups, or logs are accessible to others. In a health-agent skill, that risk is more serious because the stored credentials enable access to a healthcare-adjacent data integration handling sensitive wellness data.

Content

Scanner excerpt · scripts/fitbit_setup.py (reported line 54)May include surrounding context.

python
def save_credentials(client_id, client_secret):
    """Save credentials to .env file."""
    lines = []
    if ENV_FILE.exists():
        for line in ENV_FILE.read_text().splitlines():

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fitbit_auth.py (reported line 22)May include surrounding context.

python
from dotenv import load_dotenv

BASE_DIR = Path(__file__).parent.parent
load_dotenv(BASE_DIR / ".env")

DATA_DIR = BASE_DIR / "data" / "user_default"
TOKEN_FILE = BASE_DIR / "data" / "fitbit_token.json"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fitbit_auth.py (reported line 112)May include surrounding context.

python
from dotenv import load_dotenv

BASE_DIR = Path(__file__).parent.parent
load_dotenv(BASE_DIR / ".env")

DATA_DIR = BASE_DIR / "data" / "user_default"
TOKEN_FILE = BASE_DIR / "data" / "fitbit_token.json"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fitbit_query.py (reported line 25)May include surrounding context.

python
from dotenv import load_dotenv

BASE_DIR = Path(__file__).parent.parent
load_dotenv(BASE_DIR / ".env")

DATA_DIR = BASE_DIR / "data" / "user_default"
TOKEN_FILE = BASE_DIR / "data" / "fitbit_token.json"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fitbit_setup.py (reported line 25)May include surrounding context.

python
from dotenv import load_dotenv

BASE_DIR = Path(__file__).parent.parent
load_dotenv(BASE_DIR / ".env")

DATA_DIR = BASE_DIR / "data" / "user_default"
TOKEN_FILE = BASE_DIR / "data" / "fitbit_token.json"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/fitbit_sync.py (reported line 14)May include surrounding context.

python
from dotenv import load_dotenv

BASE_DIR = Path(__file__).parent.parent
load_dotenv(BASE_DIR / ".env")

DATA_DIR = BASE_DIR / "data" / "user_default"
TOKEN_FILE = BASE_DIR / "data" / "fitbit_token.json"

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The usage examples are broad, natural-language requests such as asking about sleep, heart rate trends, or weekly summaries. In an agent ecosystem, this can cause the skill to activate on ordinary conversation without clear user intent, increasing the chance that sensitive health data is accessed or summarized unexpectedly.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README says the skill works with 'any model — Claude, GPT, Gemini' while also claiming 'Your health data stays local on your machine' and that the agent 'processes everything locally.' If a cloud-hosted model is used, prompts or derived health data may leave the machine, so the privacy claim is misleading and can cause users to disclose sensitive medical information under false assumptions.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill invokes local scripts, reads and writes data during setup/sync/onboarding, and interacts with Fitbit authorization flows, yet it declares no explicit tool/permission scope. That mismatch weakens least-privilege controls and makes it harder for the host to constrain file, environment, and network access for a skill handling sensitive health data and credentials.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The setup text says the flow should begin when the user says /health_setup or asks to connect their Fitbit, which broadens activation beyond an explicit command. In a sensitive skill, vague semantic triggering can cause the agent to enter credential-collection and authorization flows unexpectedly, increasing the chance of accidental invocation or prompt-confusion-driven misuse.

Content

No source excerpt is available for this finding.