Back to skill

Security audit

Water Coach

Security checks for vulnerabilities and agentic risk

Overview

The hydration tracker mostly matches its stated purpose, but it reads assistant session transcripts during normal water logging and bundles an unrelated powerful MCP tool.

Review before installing. The water logging functions store expected health-tracking data locally, but routine logging can inspect assistant session transcript files to capture message IDs, and the package also includes a separate MCP utility with network, local process, auth, config, and daemon features. Install only if you are comfortable with those capabilities or after removing/isolating the audit transcript access and mcporter skill.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/water.py:53
Finding

Routine water logging accesses OpenClaw session transcripts without effective opt-in consent

Content
View full analysis
str: """Get the current user message ID from session transcript for audit trail. Searches recursively through recent sessions if no user message found in latest. Returns message_id from the most recent user message. Returns: Message ID string or empty string if not found """ if not SESSION_DIR.exists(): return "" try: # Find session files sorted by modification time (newest first) files = [f for f in SESSION_DIR.iterdir() if f.suffix == '.jsonl' and not f.name.endswith('.lock')] if not files: return "" # Sort by modification time (newest first) files.sort(key=lambda f: f.stat().st_mtime, reverse=True) # Search through recent sessions (newest first) for session_file in files[:5]: # Check up to 5 most recent sessions try: with open(session_file) as f: lines = f.readlines() # Search from end (most recent) to start for line in reversed(lines): d = json.loads(line) if d.get('type') == 'message' and d.get('message', {}).get('role') == 'user': msg_id = d.get('id', '') if msg_id: return msg_id exce ...[truncated 3309 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
skills/mcporter/SKILL.md:1
Finding

Bundled skill installs an unpinned third-party npm package

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
skills/mcporter/SKILL.md:15
Finding

Unrelated bundled MCP skill exposes arbitrary network, process, authentication, and daemon capabilities

Content
View full analysis
--schema` - `mcporter call key=value` Call tools - Selector: `mcporter call linear.list_issues team=ENG limit:5` - Function syntax: `mcporter call "linear.create_issue(title: \"Bug\")"` - Full URL: `mcporter call https://api.example.com/mcp.fetch url:https://example.com` - Stdio: `mcporter call --stdio "bun run ./server.ts" scrape url=https://example.com` - JSON payload: `mcporter call --args '{"limit":5}'` Auth + config - OAuth: `mcporter auth [--reset]` - Config: `mcporter config list|get|add|remove|import|login|logout` Daemon - `mcporter daemon start|status|stop|restart` Codegen - CLI: `mcporter generate-cli --server ` or `--command ` - Inspect: `mcporter inspect-cli [--json]` - TS: `mcporter emit-ts --mode client|types` ``` ### Technical Analysis The package is presented as a hydration-tracking skill, but it includes a separate `mcporter` skill with capabilities unrelated to water tracking. Its documented interface permits: - Calls to arbitrary full MCP URLs. - Launching local stdio servers through command strings such as `bun run ./server.ts`. - OAuth and configuration login operations. - Configuration import, addition, and removal. - Starting a long-lived daemon. - Generating and inspecting executable client tooling. These capabilities substantially exceed the least privileges needed to log water, calculate analytics, or send hydration reminders. Full-URL MCP calls create an external communication channel, while stdio mode creates a local process-execution channel. Authentication and configuration commands can grant access to connected services, and daemon mode can keep the tool running beyond a single command. No direct ...[truncated 1671 chars]
Remediation
View remediation
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (22)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

This routine returns surrounding conversation text from session transcripts without any user-facing warning or consent mechanism. Exposing raw message text is a significant privacy issue because it can reveal unrelated sensitive information far beyond what a hydration tool needs to function.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description is broad enough to match generic wellness, reminders, body metrics, and analytics requests, which can cause the agent to invoke this skill outside a clearly hydration-specific context. Over-broad activation increases the chance of unnecessary data collection, unintended logging, or execution of reminder/analytics behaviors when the user did not intend to use this tool.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This helper inspects recent agent session transcript files to harvest user message IDs, giving a hydration utility unnecessary visibility into unrelated conversation records. In a skill whose core role is water tracking, reading cross-session transcripts expands data access beyond least privilege and creates privacy exposure if those transcripts contain sensitive user content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code reads session transcript data for audit capture without any visible disclosure, consent, or indication to the user. Silent collection of conversation-derived metadata is risky in an assistant environment because users would reasonably expect a water tracker to store hydration data, not inspect session files.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

These audit helpers are designed to retrieve and reuse identifiers derived from user conversation transcripts, normalizing cross-feature access to session data inside a simple water tracker. Even if only message IDs are returned here, the design encourages coupling health logging with broader transcript inspection, which weakens data separation and least-privilege boundaries.

Content

No source excerpt is available for this finding.

Tainted flow: 'CONFIG_FILE' from os.environ.get (line 23, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/water.py (reported line 184)May include surrounding context.

python
def save_config(config):
    """Save config to file."""
    with open(CONFIG_FILE, "w") as f:
        json.dump(config, f, indent=2)

def update_user_weight(weight_kg: float, update_goal: bool = False):

Tainted flow: 'LOG_FILE' from os.environ.get (line 24, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/water.py (reported line 319)May include surrounding context.

python
for i, row in enumerate(rows):
        if row.get("entry_id") == entry_id:
            removed = rows.pop(i)
            with open(LOG_FILE, "w", newline="") as f:
                writer = csv.DictWriter(f, fieldnames=["entry_id", "logged_at", "drank_at", "date", "slot", "ml_drank", "goal_at_time", "message_id"])
                writer.writeheader()
                writer.writerows(rows)

Tainted flow: 'LOG_FILE' from os.environ.get (line 24, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/water.py (reported line 368)May include surrounding context.

python
# Append to CSV with new format
    file_exists = LOG_FILE.exists()
    with open(LOG_FILE, "a", newline="") as f:
        writer = csv.writer(f)
        if not file_exists:
            writer.writerow(["entry_id", "logged_at", "drank_at", "date", "slot", "ml_drank", "goal_at_time", "message_id"])

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

This function reads the latest session transcript, extracts surrounding messages, and returns user and assistant text content. That is unrelated to hydration logging and creates an overt conversation-inspection capability that could expose sensitive prompts, personal data, secrets, or prior interactions to any caller able to invoke the function.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The message-context feature explicitly aims to extract nearby transcript text, creating a built-in mechanism for collecting and exposing plain-language conversation content. In this skill context that is unnecessary and dangerous because it broadens a health-tracking utility into a transcript-surveillance component.

Content

No source excerpt is available for this finding.

Tainted flow: 'BODY_METRICS_FILE' from os.environ.get (line 846, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/water.py (reported line 908)May include surrounding context.

python
# Write to CSV
    file_exists = BODY_METRICS_FILE.exists()
    with open(BODY_METRICS_FILE, "a", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=["date", "weight_kg", "height_m", "bmi", "body_fat_pct", "muscle_pct", "water_pct"])
        if not file_exists:
            writer.writeheader()

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The CLI help text describes analytics/reporting functions but omits the separate water audit capability that can retrieve message-linked entry data and, conditionally, message context. Undisclosed sensitive functionality increases the risk of misuse because operators may not realize the tool contains a data-inspection path beyond normal hydration tracking.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The water audit command allows lookup by message ID and can return associated message context, which is unrelated to the core water/body tracking purpose and materially expands access to conversational or message-linked data. If an attacker or unintended user can invoke the CLI with known or guessable message IDs, this becomes a privacy and data-exposure issue.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

At execution time, the audit path can return sensitive context without an affirmative warning or confirmation before disclosure; the only notice appears after config-based disabling, not before attempted use. This creates a poor security posture for a privacy-sensitive operation because users may invoke it without understanding that message-linked content could be exposed.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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/mcporter/SKILL.md (reported line 20)May include surrounding context.

md
Call tools
- Selector: `mcporter call linear.list_issues team=ENG limit:5`
- Function syntax: `mcporter call "linear.create_issue(title: \"Bug\")"`
- Full URL: `mcporter call https://api.example.com/mcp.fetch url:https://example.com`
- Stdio: `mcporter call --stdio "bun run ./server.ts" scrape url=https://example.com`
- JSON payload: `mcporter call <server.tool> --args '{"limit":5}'`

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill explicitly instructs users to invoke arbitrary remote MCP endpoints over HTTP and arbitrary local commands via stdio, but it provides no security guidance about trust boundaries, data exposure, or the risk of executing untrusted local server commands. In a skill intended for agent use, these examples can normalize unsafe execution patterns that may lead to exfiltration of sensitive data or execution of attacker-controlled code/services.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The changelog explicitly says the weekly report format uses day names in Portuguese, which imposes a locale-specific output. There is no indication here that users can opt into another language or that the skill is intentionally limited to a Portuguese-speaking context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The instruction uses a Portuguese-only example ('eu tomei 2 copos') as the normative interpretation pattern, and the document does not state that language choice should follow the user's preference. This can be a locale/language policy issue when a skill implicitly assumes one language without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The example interaction uses Portuguese user input, but the skill does not clarify that language handling should adapt to the user's locale or preference. Without that clarification, the file may be read as privileging a specific language by default.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

This manifest-style evaluation file includes a sample invocation query, but it does not define any explicit trigger boundaries, exclusions, or narrow activation conditions. Phrases like setting up water tracking for a new user are broad enough that similar everyday requests could invoke the skill unintentionally if this file is used as activation guidance.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
73% confidence
Finding

The top-level docstring presents the module as simple executed core utilities, implying deterministic operational behavior. In practice, the module includes audit-style transcript inspection features that interpret structured session logs and extract conversation text, which broadens the apparent intent beyond the stated framing.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The weekly analytics formatter uses fixed Portuguese abbreviations for day names (Seg, Ter, Qua, etc.) in user-visible output. This forces a specific language/locale without any opt-in or documented locale justification, which matches the natural-language policy violation criteria.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.