Back to skill

Security audit

emotional-persona

Security checks for vulnerabilities and agentic risk

Overview

The skill is broadly aligned with an emotional-memory persona, but it should be reviewed because it persists sensitive wellness/crisis context and its helper scripts expose caller input to Python code execution.

Install only if you are comfortable with local plaintext emotional-memory files and review the scripts before use. Do not use the helper scripts with untrusted input until the Python interpolation bugs are fixed, and require explicit user consent before storing personal or crisis-related observations.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/emotion_memory.sh:43
Finding
Arbitrary Python Code Execution Through Memory Manager Arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/emotion_memory.sh:43-50, 57-72, 109-119, 124-137` **Vulnerability Type**: User-controlled data interpolated into dynamically generated Python source **Risk Level**: High ### Vulnerable Code ```bash python3 -c " import json, sys with open('$MEMORY_FILE', 'r') as f: data = json.load(f) entry = json.loads('''$ENTRY''') data['patterns'].append(entry) with open('$MEMORY_FILE', 'w') as f: json.dump(data, f, indent=2) print(f'Stored: {entry[\"id\"]}') " ``` ```bash python3 -c " import json with open('$MEMORY_FILE', 'r') as f: data = json.load(f) query = '$QUERY'.lower() results = [] for p in data['patterns']: if query in p.get('observation','').lower() or any(query in t.lower() for t in p.get('tags',[])): results.append(p) if not results: print('No matching patterns found.') else: for r in results[-10:]: print(f\"[{r['timestamp']}] ({r['importance']}) {r['observation']}\") if r.get('tags'): print(f\" tags: {', '.join(r['tags'])}\") " ``` ```bash python3 -c " import json with open('$MEMORY_FILE', 'r') as f: data = json.load(f) patterns = data.get('patterns', []) for p in patterns[-$LIMIT:]: print(f\"[{p['id']}] {p['timestamp']} ({p['importance']})\") print(f\" {p['observation']}\") if p.get('tags'): print(f\" tags: {', '.join(p['tags'])}\") " ``` ```bash python3 -c " import json with open('$MEMORY_FILE', 'r') as f: data = json.load(f) before = len(data['patterns']) data['patterns'] = [p for p in data['patterns'] if p['id'] != '$MEMORY_ID'] after = len(data['patterns']) with open('$MEMORY_FILE', 'w') as f: json.dump(data, f, indent=2) if before > after: print(f'Forgotten: $MEMORY_ID') else: print(f'Not found: $MEMORY_ID') " ``` ### Technical Analysis Arguments controlled by the caller are inserted directly into source code supplied to `python3 -c`. The affected values include: - `$ENTRY`, which conta ...[truncated 2109 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Eliminate interpolation of arguments into Python source. - Pass all caller-controlled values as positional arguments: ```bash python3 - "$MEMORY_FILE" "$QUERY" <<'PY' import json import sys memory_file = sys.argv[1] query = sys.argv[2].lower() with open(memory_file, "r", encoding="utf-8") as f: data = json.load(f) PY ``` - Pass structured entries through standard input and parse them with `json.load(sys.stdin)` instead of embedding JSON inside a Python string literal. - Parse `--limit` in Bash or Python as an integer and enforce a safe range, such as `1` through `100`. - Treat memory IDs as data, not source code. Optionally validate them against the expected identifier format, such as `^em_[0-9]+_[0-9]+$`. - Validate option arity before reading `$2`, and reject unknown options instead of silently ignoring them. - Add regression tests containing quotes, triple quotes, line breaks, semicolons, backslashes, and Python syntax in every argument. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/emotion_report.sh:121
Finding
Arbitrary Python Code Execution Through the Report Since Parameter<![CDATA[ ## Vulnerability Details **File Location**: `scripts/emotion_report.sh:121-142` **Vulnerability Type**: User-controlled date argument interpolated into dynamically generated Python source **Risk Level**: High ### Vulnerable Code ```bash python3 -c " import json from collections import Counter with open('$MEMORY_FILE', 'r') as f: data = json.load(f) anchors = ['grounding','softness','connection','release','courage'] counts = Counter() for p in data.get('patterns',[]): ts = p.get('timestamp','') if '$SINCE' and ts < '$SINCE': continue for t in p.get('tags',[]): if t.lower() in anchors: counts[t.lower()] += 1 total = sum(counts.values()) or 1 print('Anchor Distribution (all time):') for a in anchors: c = counts.get(a,0) pct = int(c/total*100) bar = '█' * (pct//5) + '░' * (20-pct//5) print(f' {a.capitalize():12s} {bar} {pct:3d}% ({c})') " ``` ### Technical Analysis The value supplied to `anchors --since` is assigned to `$SINCE` and inserted twice into single-quoted Python string literals. No date-format validation or source-code escaping is performed. A quote in the supplied date can terminate the intended literal. Additional Python expressions or statements can then become executable source in the `python3 -c` program. The safe heredoc-based approach used by `generate_report()` demonstrates that dynamic source construction is unnecessary. ### Attack Path 1. An attacker causes the Skill or a user to invoke: ```bash ./scripts/emotion_report.sh anchors --since "<crafted value>" ``` 2. The crafted value includes a quote and Python syntax appropriate to the conditional-expression context. 3. Bash substitutes the value into both occurrences of: ```python if '$SINCE' and ts < '$SINCE': ``` 4. The generated source is parsed by Python, including the attacker-provided syntax. 5. Injected Python can invoke operating-system commands or directly read and modify accessible files. ### ...[truncated 556 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pass the date as a positional argument rather than inserting it into Python source: ```bash python3 - "$MEMORY_FILE" "$SINCE" <<'PY' import json import sys from datetime import datetime memory_file = sys.argv[1] since = sys.argv[2] if since: datetime.strptime(since, "%Y-%m-%d") with open(memory_file, "r", encoding="utf-8") as f: data = json.load(f) PY ``` - Require a strict `YYYY-MM-DD` date and reject malformed input. - Reuse the fixed heredoc and `sys.argv` pattern already implemented in `generate_report()`. - Add tests using quotes, newlines, Python operators, invalid dates, and unexpectedly long values. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/emotion_memory.sh:5
Finding
Sensitive Emotional Records Are Stored Without Enforced Retention or Explicit File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/emotion_memory.sh:5-9, 48-50` **Vulnerability Type**: Plaintext sensitive-data retention and filesystem permission hardening failure **Risk Level**: Medium ### Relevant Code and Configuration ```bash DATA_DIR="${SCRIPT_DIR}/../data" MEMORY_FILE="${DATA_DIR}/emotional_memory.json" mkdir -p "$DATA_DIR" [ -f "$MEMORY_FILE" ] || echo '{"patterns":[],"growth":[],"preferences":[]}' > "$MEMORY_FILE" ``` ```python data['patterns'].append(entry) with open('$MEMORY_FILE', 'w') as f: json.dump(data, f, indent=2) ``` The documentation expressly recommends retaining sensitive personal context: ```markdown What to remember: - Recurring emotional patterns ("always stressed on Sundays") - Effective anchors ("Softness works better than Courage for this user") - Personal context that matters ("user's dog passed away last month") - Growth indicators ("user is handling conflict better than 3 weeks ago") ``` It also directs the agent to retain the occurrence of crisis support: ```markdown 6. **Log for memory** — store that crisis support was provided (not details) ``` The example configuration advertises a retention period: ```json "memory": { "store_patterns": true, "store_growth": true, "retention_days": 180 } ``` ### Technical Analysis The memory manager stores personal emotional observations in plaintext JSON. The directory and file are created without explicit restrictive modes, so their actual permissions depend on the runtime's umask and surrounding directory permissions. In addition, `retention_days` is present in the configuration and documentation but is never read or enforced by the reviewed scripts. Records therefore remain until a caller explicitly invokes `forget` with a specific memory ID. This behavior can cause sensitive records to persist indefinitely despite an apparent 180-day retention policy. ### Attack Path 1. The agent follows the documented workflow and records emotional ...[truncated 976 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create the storage directory and file with explicit least-privilege modes: ```bash install -d -m 0700 "$DATA_DIR" if [[ ! -f "$MEMORY_FILE" ]]; then umask 077 printf '%s\n' '{"patterns":[],"growth":[],"preferences":[]}' > "$MEMORY_FILE" chmod 0600 "$MEMORY_FILE" fi ``` - Verify and repair permissions before every read or write. - Implement `retention_days` by parsing timestamps and deleting expired records during startup, storage, reporting, or a dedicated cleanup action. - Use atomic writes through a securely created temporary file in the same directory, then set mode `0600` and rename it over the destination. - Obtain explicit user consent before retaining emotional or crisis-related context. - Minimize stored content and avoid retaining crisis information unless operationally necessary. - Provide a command to erase all records, not only one known memory ID. - Consider encryption at rest where the host's threat model requires protection from offline or cross-account access. ]]>
Vulnerability Patterns
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The code only manages a JSON file of observations labeled as emotional patterns. It supports storing notes, searching by text/tags, listing entries, summarizing counts/tags, and forgetting by ID. While this partially aligns with the 'emotional memory' portion of the description, it does not implement moods, emotional memory influencing behavior, evolving personality traits, or any mechanism that gives an AI agent a living emotional personality. The primary purpose is closer to a simple emotional-memory datastore than a full emotional-personality system, so the description materially overstates the behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The declared description suggests a runtime emotional-persona system that actively gives an AI agent evolving moods, emotional memory, and personality traits during interaction. The supplied code does not implement those behaviors. Instead, it reads existing local JSON data files and produces retrospective summaries such as anchor distributions, recent observations, and growth indicators. While the report references emotional data, its actual purpose is reporting/analysis of previously stored emotional records, not creating or operating an emotional personality for an agent. This is a material purpose mismatch rather than a minor implementation detail.

Missing User Warnings

High
Confidence
97% confidence
Finding
The safety protocol directs the agent to log that crisis support was provided, which creates a persistent record of a highly sensitive mental-health interaction without clear notice to the user. Crisis-related metadata is especially dangerous because even minimal logging can reveal suicidal ideation or self-harm risk and may expose users if storage is later accessed or repurposed.

Intent-Code Divergence

High
Confidence
96% confidence
Finding
The document claims the skill is not a mood tracker, yet earlier sections define cross-session retention, summaries, pattern detection, and weekly emotional reports. That contradiction is dangerous because it can mislead deployers and users about the true extent of sensitive mental-health-adjacent data collection, undermining informed consent and safe governance.

Lp3

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding
The skill declares shell/script capabilities and references scripts that store, search, summarize, and forget memory, but it does not explicitly declare any tool scope or permissions boundary. In an agent environment, undeclared read/write capability increases the risk of overbroad file access and makes it harder for operators to constrain where sensitive emotional data is persisted.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs agents to store cross-session emotional patterns and highly personal context such as grief and recurring stress without an explicit user-facing privacy notice or consent flow. In a wellness/companion context, this is particularly sensitive because users are likely to disclose intimate information while perceiving the interaction as supportive rather than as data collection.

Ssd 3

Medium
Confidence
93% confidence
Finding
The skill explicitly tells the agent to retain recurring emotional patterns, effective anchors, and sensitive personal context across sessions. Persistent storage and later summarization of this kind of emotional profile increases the blast radius of any misuse, overcollection, or unauthorized access, especially for companion-style agents that invite vulnerable disclosures.

Ssd 3

Medium
Confidence
96% confidence
Finding
Logging that crisis support was provided retains sensitive mental-health interaction data and creates a durable signal that the user may have experienced acute risk. Even without details, this kind of event retention can be highly revealing and is disproportionate unless there is a clearly disclosed, necessary safety or compliance reason.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The crisis flow hard-codes U.S.-specific resources without checking user locale or clarifying that the guidance is U.S.-only. In a safety-critical context, incorrect regional guidance can delay access to appropriate emergency support and create harm for users outside the United States.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The skill expands from a persona layer into emotional wellness reporting and growth tracking, which materially broadens the sensitivity of collected data and the inferences generated about users. In the context of companion and wellness bots, this scope expansion is dangerous because operators may deploy it expecting style modulation, while it also performs quasi-mental-health profiling.

Ssd 3

Medium
Confidence
91% confidence
Finding
Weekly reports aggregate anchor distributions, patterns, and growth indicators derived from user interactions, effectively transforming raw conversations into behavioral and emotional profiling artifacts. These summaries can expose intimate inferences beyond what users expect from a persona feature and make secondary use or unauthorized disclosure more damaging.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The crisis detection relies on a short, exact-match style keyword list for self-harm intent, which is easy to evade through paraphrasing, slang, misspellings, or indirect statements. In an emotional-persona skill intended for companion or wellness-style interactions, missing a crisis cue can lead the agent to continue emotionally engaging instead of switching to a safer response path, increasing harm during high-risk conversations.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script persistently stores free-form user observations to disk in an emotional memory file without any notice, consent prompt, retention controls, or visibility into where sensitive content is kept. In the context of a companion or wellness-oriented emotional persona, those observations may contain highly personal or mental-health-adjacent information, making silent persistence a meaningful privacy risk if the host is shared, backed up, or later accessed by another process or user.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This shell script reads local files containing emotional memory and state data, then prints summaries and recent observations to stdout. Although the behavior is central to the script's purpose, there is no visible warning, prompt, or explanatory comment/docstring informing the user that potentially sensitive personal wellness data will be surfaced in terminal output.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The forget command permanently removes matching entries and writes the modified dataset back to disk. While it prints the result afterward, there is no confirmation prompt or advance warning that the action is irreversible.

Static analysis

No suspicious patterns detected.