T09 · Insecure Skill Coding Practices
- Location
scripts/buddy.py:886- Finding
Unsanitized User-Controlled Content Can Inject Terminal Escape Sequences
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This appears to be a local companion skill, but it automatically builds persistent diary-like records from user behavior and has unsafe state/terminal handling that users should review before installing.
Review this before installing if you do not want a skill to keep a local, behavior-derived companion history. Use explicit slash commands, avoid storing sensitive task details in buddy names/context/profile fields, consider setting BUDDY_STATE_FILE to an isolated path, and inspect or remove ~/.buddy_mode_state.json if you want to clear its saved data.
scripts/buddy.py:886Unsanitized User-Controlled Content Can Inject Terminal Escape Sequences
scripts/check.sh:35Validation Script Modifies the User’s Production State File
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.
- Multiple unlocks in a single session. One unlock per session is a special event. Two is the absolute maximum for an unusually varied session. Three or more means the threshold is too low.
- When the user just started. The first buddy is free; the second should take at least a few real interactions to arrive.
The ideal pacing: a regular user gets a new buddy every **3-5 sessions**. After a month, they have 8-15 buddies, each with a clear memory of when and why it appeared. This feels like a growing collection, not a firehose.
## Personality constraints
The README advertises that buddies remember shared experiences, grow from user habits, and persist memory, but it does not clearly disclose what data is retained, for how long, or how users can inspect and delete it. Because the feature is explicitly based on behavioral history, missing privacy notice and controls can lead to silent collection or retention of sensitive workflow patterns.
The trigger list includes broad natural-language phrases like "enable buddy mode" and "be my coding buddy" that can plausibly occur in ordinary conversation, increasing the chance of unintended activation. In a skill that adds persistent memory and behavior changes, accidental invocation can expose user context to the skill or cause state changes without clear user intent.
The skill instructs the agent to invoke local scripts and maintain state, but the manifest does not declare any explicit tool scope or permissions. That mismatch can cause the runtime to grant broader-than-necessary capabilities by default or make the skill's file, environment, and persistence behavior insufficiently reviewable.
The direct activation section includes loose natural-language triggers such as asking for a mascot, companion, collectible, or more lively session, which are ambiguous and easy to match unintentionally. In context, accidental activation matters because the skill then begins tracking habits, generating persistent state, and modifying output style across the session.
The ambient activation rules are extremely broad and allow the buddy behavior to trigger from ordinary activities like reminders, research, debugging, travel, shopping, or casual check-ins. That creates a high risk of unexpected activation and silent collection of behavioral context outside clear user consent, especially because the skill is designed to persist observations over time.
The skill tells the system to notice repeated user actions within a session and comment on patterns in their behavior. While less severe than cross-session storage, this still encourages behavioral profiling and can surface sensitive work habits or activity patterns the user did not expect to be tracked or reflected back.
This section explicitly directs the system to store detailed cross-session records including obtained context, memorable moments, times shown, and diary-like notes tied to the user's habits and actions. Even if framed as a game mechanic, this creates a persistent behavioral profile that can reveal routines, interests, work patterns, and potentially sensitive personal details over time.
The skill explicitly states that the collection should function as a personal diary built from the user's story, habits, and memorable events. That purpose materially increases privacy risk because it incentivizes long-lived storage of personalized, behavior-derived notes rather than transient UX state.
The skill persists companion state and user-derived context to a local file even though the described functionality centers on interactive generation/display. This creates an undisclosed data retention surface that can store behavioral or contextual user information on disk, increasing privacy risk and exposure if the host is shared or compromised.
The language-selection logic maps the user-visible 'mixed' option directly to 'zh', causing the skill to force Chinese output rather than honoring an actual mixed or user-chosen locale. This is a natural-language policy issue because it imposes a specific language without clear opt-in to that exact behavior.
State is auto-saved to disk during normal operations without clear warning or consent, despite including fields like obtained_context, memorable notes, and unlocked history. This is a privacy and transparency issue rather than a memory-safety bug, but in a companion skill the mismatch between expected ephemeral interaction and silent persistence makes it materially risky.
The state file path is derived from the BUDDY_STATE_FILE environment variable and then written to without validation. If an attacker can influence the execution environment, they can redirect writes to arbitrary filesystem locations writable by the process, causing unauthorized file overwrite or corruption; the skill context makes this more concerning because the file is written automatically during normal buddy interactions.
def save_state(state: dict) -> None:
STATE_FILE.write_text(json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8")
def add_to_collection(theme: str, name: str, custom_profile=None, context: str = "") -> dict:
The register command accepts an arbitrary JSON profile and stores it as a custom pool, extending the skill beyond simple display into persistent, user-controlled content registration. In this context it is not direct code execution, but it broadens attack surface for data abuse, oversized input, malformed state, and persistence of deceptive or harmful content in a skill that users would expect to be a lightweight companion feature.
Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.
- Buddies react to what you are actually doing, not random flavor text.
- Stats grow over time based on shared experiences (+Focus from debugging, +Warmth from check-ins).
- Each buddy remembers when and why it appeared, building a personal history.
- New species and pools are generated dynamically from user behavior — not limited to a fixed catalog.
- Rarity has luck rolls: the same species can drop at different tiers.
- Cards are narrow and sidebar-friendly with rarity-styled frames.
- Supports Chinese, English, or mixed flavor text.