Back to skill

Security audit

Bean Whisperer

Security checks for vulnerabilities and agentic risk

Overview

The skill has a real coffee-machine profile purpose, but it needs Review because it can pull untrusted Discord profiles and apply or delete machine profiles without enough validation or confirmation.

Review this skill carefully before installing. Use it only if you are comfortable giving an agent access to your GaggiMate profile controls and a Discord credential. Do not push downloaded community profiles without manually checking all temperature, pressure, flow, duration, and stop values, and avoid delete or push commands unless you have confirmed the exact profile ID and have a backup/export.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/discord-profiles.py:219
Finding

Path Traversal Through Untrusted Discord Attachment Filenames

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/gaggimate-ws.py:91
Finding

Untrusted Profiles Can Be Deployed to a Physical Appliance Without Safety Validation

Content
View full analysis
dict | None: async with aiohttp.ClientSession() as session, session.get(url) as resp: if resp.status != 200: return None try: return json.loads(await resp.text()) except Exception: return None ``` Profiles are then loaded and sent to the machine without validation: ```python async def save_profile(filepath: str) -> dict: with open(filepath) as f: profile = json.load(f) # Ensure it has an ID if not profile.get("id"): profile["id"] = str(uuid.uuid4()) result = await send_and_receive({"tp": "req:profiles:save", "profile": profile}) if result.get("error"): print(f"Error saving: {result['error']}", file=sys.stderr) sys.exit(1) saved = result.get("profile", profile) print(f"Saved: {saved.get('label', 'unnamed')} ({saved.get('id', '?')[:8]})") return saved ``` The full deployment flow immediately favorites and selects the uploaded profile: ```python async def push_profile(filepath: str): """Save, favorite, and select a profile in one go.""" saved = await save_profile(filepath) pid = saved.get("id", "") if pid: await favorite_profile(pid) await select_profile(pid) print(f"\n✅ Profile '{saved.get('label', '')}' deployed and ready to brew!") ``` ### Technical Analysis The Discord community is an external trust boundary. Parsing an attachment with `json.loads` verifies only JSON syntax; it does not establish that the object is a valid or safe espresso-machine profile. `save_profile` does not validate ...[truncated 2102 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate-profile.py:379
Finding

Profile Generator Does Not Enforce Documented Numeric Safety Bounds

Content
View full analysis
Remediation
View remediation
float: number = float(value) if not math.isfinite(number): raise argparse.ArgumentTypeError("Value must be finite") if not minimum <= number <= maximum: raise argparse.ArgumentTypeError( f"Value must be between {minimum} and {maximum}" ) return number return parse ``` 2. Apply suitable validators to dose, ratio, and temperature. 3. Distinguish automatic selection from numeric values with `None` rather than using zero as a sentinel. 4. Serialize with strict JSON behavior: ```python output = json.dumps(profile, indent=2, allow_nan=False) ``` 5. Validate the complete generated object against the strengthened schema and semantic safety policy. 6. Re-run the same validation in `gaggimate-ws.py`; validation only at generation time would not protect manually edited or downloaded profiles. 7. Add tests covering negative, excessive, `NaN`, positive-infinity, and negative-infinity inputs. ]]>

T08 · Insecure Dependencies

Note
Location
pyproject.toml:7
Finding

Runtime Dependencies Are Installed Without Reproducible Version Pinning

Content
View full analysis
=12.0", "aiohttp>=3.9", ] ``` The documentation also recommends resolving the latest available versions: ```bash pip install websockets aiohttp ``` and: ```bash pip3 install websockets ``` ### Technical Analysis The dependencies have only lower bounds and the project contains no reviewed lockfile or hash-verified requirements. Installation can therefore resolve future package versions that were not part of this audit. The package names match the imports and no evidence of typosquatting, dependency confusion, or a currently malicious package was found. The risk is the non-reproducible installation process rather than a confirmed malicious dependency. Because Python package installation and imports execute code with the installing user’s privileges, compromise of a future package release or package-index account could affect Skill users. ### Attack Path 1. A user follows the documented installation instructions. 2. The package index resolves the newest versions satisfying the broad lower bounds. 3. A future version is compromised, malicious, or unexpectedly incompatible. 4. Package installation hooks or imported package code run under the user’s account. 5. The compromised dependency can act with the same filesystem and network privileges as the Skill process. ### Impact Assessment A compromised dependency could access files and environment variables available to the user, including `DISCORD_TOKEN`, communicate over the network, alter generated profiles, or issue unintended machine-control requests. No such compromise was observed in the audited source. This finding represents avoidable supply-chain exposure caused by the absence of reproducible depende ...[truncated 19 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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 (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

If the actual implementation lacks the machine interaction, photo handling, and profile-management capabilities promised by the skill description, users may be induced to rely on a skill that behaves differently than advertised. In security terms, behavior/description drift weakens informed consent and can mask undeclared data handling or external dependencies.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

If the actual implementation lacks the machine interaction, photo handling, and profile-management capabilities promised by the skill description, users may be induced to rely on a skill that behaves differently than advertised. In security terms, behavior/description drift weakens informed consent and can mask undeclared data handling or external dependencies.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

If the actual implementation lacks the machine interaction, photo handling, and profile-management capabilities promised by the skill description, users may be induced to rely on a skill that behaves differently than advertised. In security terms, behavior/description drift weakens informed consent and can mask undeclared data handling or external dependencies.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The description emphasizes that the tool can 'push' generated pressure profiles to a machine over WebSocket, but it does not present a prominent warning that this changes device state and may affect brewing behavior immediately. In a hardware-control skill, missing user-facing caution and confirmation increases the risk of unintended machine reconfiguration or unsafe assumptions about what the assistant may do automatically.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README advertises very broad natural-language triggers such as 'new bean', 'shot was sour', 'too acidic', and 'dial it in', which can cause the skill to activate in contexts where the user did not clearly intend machine-related actions. In this skill's context, activation can lead to profile generation, modification, or eventual device-state changes on a connected espresso machine, so accidental invocation has meaningful operational consequences.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The CLI documents a delete operation for machine profiles without warning that the action is destructive or whether recovery is possible. Because this skill manages profiles on a physical device, accidental or misunderstood deletion can remove tuned configurations and disrupt the user's workflow, especially if deletion is triggered through conversational use or copied commands.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill documents capabilities to read environment variables, read/write local files, and use network services, but it does not declare any explicit tool scope or permission boundaries. That creates an authorization gap where a reviewer or runtime may not clearly restrict sensitive actions such as using DISCORD_TOKEN, writing arbitrary profile files, or connecting to local machine and Discord endpoints.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger list includes broad, conversational phrases like 'new coffee', 'too acidic', and 'dial it in', which can cause accidental invocation in unrelated contexts. Because the skill can perform network access, file writes, and potentially machine-management actions, overbroad triggering increases the chance of unintended sensitive operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill documents destructive deletion of machine profiles without requiring explicit confirmation or a safety prompt. An accidental invocation, ambiguous profile ID, or maliciously crafted user request could result in irreversible loss of saved machine settings.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The Discord workflow introduces access to a third-party community using a bot token and permits downloading content from that service, even though the manifest centers on local machine-profile generation/management. This expands the trust boundary, exposes a secret, and creates risk of unnecessary data exfiltration or ingestion of untrusted files from Discord.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The API documentation exposes a destructive req:profiles:delete operation without any guidance to require user confirmation, soft-delete behavior, or recovery safeguards. In this skill context, the agent is explicitly allowed to manage machine profiles, so missing confirmation patterns materially increase the chance of accidental or unauthorized deletion of user-created brew profiles.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script expands the skill's behavior from generating or managing local machine brew profiles into accessing an external Discord community, enumerating threads, and downloading files. That broadens the data-access surface and introduces unsolicited network interaction with third-party content, which is risky in a skill whose stated purpose does not require external community scraping.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code retrieves a Discord user token from the environment or local config and uses it to access Discord APIs. Using a personal user token for an external service unrelated to the core bean-profile generation function creates credential exposure risk, may violate platform rules, and enables unauthorized access to community/account data if the skill is triggered unexpectedly or repurposed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script silently consumes a sensitive Discord token from either an environment variable or a local file without any user-facing notice, confirmation, or boundary on when it will be used. In the context of an agent skill, hidden credential use is dangerous because users may invoke coffee-profile functionality without realizing it authenticates to a third-party service and accesses external data on their behalf.

Content

No source excerpt is available for this finding.

Tainted flow: 'outpath' from os.environ.get (line 225, 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/discord-profiles.py (reported line 226)May include surrounding context.

python
profile = await download_attachment(a["url"])
        if profile:
            outpath = PROFILES_DIR / a["filename"]
            with open(outpath, "w") as f:
                json.dump(profile, f, indent=2)
            print(f"  ✅ {a['filename']}: {summarize_profile(profile)}")
            print(f"     → {outpath}")

Tainted flow: 'outpath' from os.environ.get (line 251, 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/discord-profiles.py (reported line 252)May include surrounding context.

python
outpath = PROFILES_DIR / fname
                    if outpath.exists():
                        outpath = PROFILES_DIR / f"{outpath.stem}_{t['id'][:8]}{outpath.suffix}"
                    with open(outpath, "w") as f:
                        json.dump(profile, f, indent=2)
                    label = profile.get("label", "unnamed")
                    print(f'  ✅ {fname}: "{label}"')

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The manifest frames the skill around taking a bean photo or name and creating/managing GaggiMate brew profiles. Line L036 expands this into web searching for origin, roast, processing, and flavor notes, which is an extra networked research capability not mentioned in the manifest.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: websockets has 4 known advisory(ies) (CVE-2018-1000518 (websockets is vulnerable to denial of service by memory exhaustion); CVE-2021-33880 (Observable Timing Discrepancy in aaugustin websockets library); CVE-2018-1000518 (aaugustin websockets version 4 contains a CWE-409: Improper Handling of Highly C) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding

The dependency specification websockets>=12.0 is not pinned to a specific version, so builds may resolve to different releases over time and make it hard to verify whether a deployed version contains a known vulnerable package release. This is primarily a supply-chain hygiene issue rather than proof of an exploitable flaw in this file, but it increases risk because security posture becomes non-deterministic and patch status cannot be reliably audited.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: aiohttp has 16 known advisory(ies) (CVE-2024-52303 (aiohttp has a memory leak when middleware is enabled when requesting a resource ); CVE-2026-54279 (aiohttp: Host-Only Cookies Become Domain Cookies After CookieJar Persistence); CVE-2026-34514 (AIOHTTP has CRLF injection through multipart part content type header constructi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
92% confidence
Finding

The dependency specification aiohttp>=3.9 is unpinned, which means the installed package version may vary by environment and time, preventing reliable confirmation that the resolved version is free of known advisories. In a network-facing skill that likely communicates with devices or services over HTTP/WebSocket, this uncertainty modestly increases exposure because vulnerable transitive or direct versions could be introduced during deployment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The persona and workflow explicitly culminate in 'User approves → push to machine' but do not require a clear user warning or confirmation guard immediately before changing a physical device's brew profile. In this context, the impact is limited because the device is an espresso machine rather than a life-critical system, but silent or insufficiently signposted profile pushes can still cause unwanted hardware behavior, wasted coffee, or unsafe hot-water operation if users do not realize settings are being applied.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.