T09 · Insecure Skill Coding Practices
- Location
scripts/discord-profiles.py:219- Finding
Path Traversal Through Untrusted Discord Attachment Filenames
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
scripts/discord-profiles.py:219Path Traversal Through Untrusted Discord Attachment Filenames
scripts/gaggimate-ws.py:91Untrusted Profiles Can Be Deployed to a Physical Appliance Without Safety Validation
scripts/generate-profile.py:379Profile Generator Does Not Enforce Documented Numeric Safety Bounds
pyproject.toml:7Runtime Dependencies Are Installed Without Reproducible Version Pinning
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
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}")
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
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}"')
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.
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.
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.
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.
No suspicious patterns detected.