Back to skill

Security audit

I Love You Mom

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its Mixtiles photo-ordering purpose, but it needs Review because it handles private WhatsApp photos, can collect photos outside the stated month, and can upload/share them with limited user control.

Review before installing. Only use it with a WhatsApp group and Cloudinary account you intend to process, verify the selected photos and recipient before upload or send, and consider fixing the date upper bound and newest-file fallback first.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (3)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/collect-photos.sh:27
Finding
Photo Collection Extends Beyond the Declared Monthly Period<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:27-37`; `scripts/collect-photos.sh:27-32` **Vulnerability Type**: `T05: Unauthorized Access and Privilege Escalation` **Risk Level**: Medium ### Vulnerable Code ```bash # Calculate first day of last month YEAR_MONTH=$(date -v-1m +%Y-%m) # macOS AFTER_DATE="${YEAR_MONTH}-01" OUTPUT_DIR=~/mixtiles-queue/${YEAR_MONTH} # Run the collection script bash <skill-dir>/scripts/collect-photos.sh "$MIXTILES_GROUP_JID" "$AFTER_DATE" "$OUTPUT_DIR" ``` ```bash MESSAGES_JSON=$(wacli messages search "*" \ --chat "$GROUP_JID" \ --type image \ --after "$AFTER_DATE" \ --limit 100 \ --json 2>/dev/null) ``` ### Technical Analysis The skill states that it collects photos from the previous month, but the search applies only a lower date boundary through `--after "$AFTER_DATE"`. It does not apply an exclusive upper boundary corresponding to the first day of the current month. Consequently, when the pipeline runs after the month changes, the search can return both previous-month photos and photos posted during the current month. This exceeds the task's documented collection scope and violates data-minimization and least-privilege principles for private family media. The `--limit 100` argument limits the number of returned messages but does not correct the date range. ### Attack Path 1. The monthly skill calculates the first day of the previous month. 2. The collection script searches for every image after that date. 3. Members post new images in the WhatsApp group during the current month. 4. The unbounded search includes those current-month images. 5. The script downloads the images to the local output directory. 6. The agent may inspect them during vision-based curation. 7. If selected, an out-of-period image may be uploaded to Cloudinary and included in the Mixtiles cart URL. No malicious group member is required; ordinary current-month activity is sufficient to trigger the scope violation. ### Impa ...[truncated 511 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Calculate and enforce both boundaries of the previous month: - Inclusive lower boundary: first day of the previous month. - Exclusive upper boundary: first day of the current month. If `wacli` supports a `--before` option, use it directly: ```bash AFTER_DATE="$(date -v-1m -v1d +%Y-%m-%d)" BEFORE_DATE="$(date -v1d +%Y-%m-%d)" wacli messages search "*" \ --chat "$GROUP_JID" \ --type image \ --after "$AFTER_DATE" \ --before "$BEFORE_DATE" \ --limit 100 \ --json ``` If no upper-bound option exists, filter message timestamps with `jq` before downloading any media. Reject messages with missing or unparseable timestamps rather than treating them as in scope. The implementation should also account for: - The intended time zone. - Whether `--after` and `--before` are inclusive or exclusive. - Pagination when more than 100 legitimate previous-month images exist. - Tests covering month and year boundaries. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/collect-photos.sh:67
Finding
Unverified Newest-File Fallback Can Select an Unrelated Photo<![CDATA[ ## Vulnerability Details **File Location**: `scripts/collect-photos.sh:67-71` **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: Medium ### Vulnerable Code ```bash # If JSON parsing fails, check if the output dir has a new file if [ -z "$FILEPATH" ] || [ "$FILEPATH" = "null" ]; then # Fallback: find most recently modified file in output dir FILEPATH=$(ls -t "$OUTPUT_DIR"/* 2>/dev/null | head -1) fi ``` ### Technical Analysis When `wacli media download` does not return a recognized path property, the script assumes that the most recently modified file in the shared output directory is the downloaded media. The implementation does not establish that the selected file: - Was created by the current download operation. - Corresponds to the current WhatsApp message. - Is an image. - Was not left over from a previous run. - Was not written concurrently by another process. A stale file can therefore be attributed to a new message. Concurrent executions create an additional race condition because one execution can select a file created by the other. The misleading comment says that the script checks for a “new file,” but no before-and-after directory comparison is performed. ### Attack Path 1. The output directory contains a preexisting file, or another process writes a file into it. 2. `wacli media download` succeeds but returns JSON without one of the recognized `path`, `filePath`, or `file` properties. 3. The fallback sorts every file in the output directory by modification time. 4. The script selects the newest file without associating it with the current message ID. 5. The unrelated path is emitted in the manifest with the current message's metadata. 6. The agent may curate the wrong file. 7. If selected, the unrelated file may be uploaded to Cloudinary and included in the externally shared Mixtiles cart. A local actor with write access to the output directory could deliberately place or touch a chosen file immedia ...[truncated 692 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Remove the newest-file fallback and fail closed when the download result does not identify a verified file. Prefer one of these designs: 1. Configure `wacli` to download each message to a unique, predetermined path derived from a safely normalized message identifier. 2. Create a unique per-message directory with `mktemp -d`, download into it, and accept a result only if exactly one regular image file appears. 3. Record a directory snapshot before the download and compare it afterward, accepting only newly created files. This is less robust than a unique directory and must still account for concurrent writers. Additional controls should include: - Validate that the resolved path is inside the expected output directory. - Verify that it is a regular file and not a symbolic link. - Verify the MIME type or image signature. - Avoid shared output directories across concurrent executions. - Use restrictive directory permissions. - Clean or archive prior-run files before collection. - Bind every accepted path to the specific message ID in a deterministic manner. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/collect-photos.sh:78
Finding
Untrusted Metadata Is Interpolated into JSON Without Escaping<![CDATA[ ## Vulnerability Details **File Location**: `scripts/collect-photos.sh:78` **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: Low ### Vulnerable Code ```bash echo "{\"id\":\"$MSG_ID\",\"sender\":\"$SENDER\",\"timestamp\":\"$TIMESTAMP\",\"filepath\":\"$FILEPATH\"}" ``` ### Technical Analysis The script constructs JSON by directly interpolating message metadata and a filesystem path into a quoted string. JSON-significant characters are not escaped. Values containing quotation marks, backslashes, newlines, tabs, or other control characters can produce invalid JSON. Because the output is piped into `jq -s '.'` while `set -euo pipefail` is active, malformed entries can cause the collection process to fail. Carefully structured values may also alter the intended JSON object shape before aggregation. Shell command substitution is not introduced by these variable expansions because the shell does not recursively execute syntax contained in variable values. The confirmed risk is JSON corruption and pipeline disruption, not direct shell command execution. ### Attack Path 1. A parsed message field or returned file path contains JSON metacharacters or control characters. 2. The value is inserted directly between JSON quotation marks. 3. The emitted line becomes malformed JSON or represents a structure different from the intended object. 4. The downstream `jq -s '.'` operation rejects or incorrectly interprets the entry. 5. With `pipefail` enabled, the script may terminate without producing a valid manifest. 6. The monthly workflow is interrupted or receives incorrect photo attribution. The practical exploitability of individual fields depends on what characters `wacli` permits in message identifiers, sender values, timestamps, and returned paths. ### Impact Assessment The primary impact is availability: one malformed value may prevent the complete photo manifest from being generated. Integrity may also be affected if a crafte ...[truncated 265 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Generate each manifest object with `jq` so all values are encoded according to JSON rules: ```bash jq -n \ --arg id "$MSG_ID" \ --arg sender "$SENDER" \ --arg timestamp "$TIMESTAMP" \ --arg filepath "$FILEPATH" \ '{ id: $id, sender: $sender, timestamp: $timestamp, filepath: $filepath }' ``` Retain the final `jq -s '.'` aggregation after replacing manual serialization. Also: - Validate required fields before serialization. - Reject unexpected field types in the original `wacli` response. - Keep diagnostic logging on standard error and JSON exclusively on standard output. - Add tests containing quotes, backslashes, whitespace, Unicode characters, and embedded newlines. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The code is a narrow photo-collection helper script, not the full declared monthly photo-to-Mixtiles pipeline. Its behavior is limited to querying WhatsApp messages via wacli, downloading image attachments, and emitting metadata. The declared description claims additional major capabilities—curation using vision, building a Mixtiles cart link, and sending that link—which are absent here. While photo collection from a WhatsApp group is consistent with part of the description, the actual code does not accurately represent the broader declared functionality.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill describes collecting photos from a WhatsApp group and uploading them to Cloudinary, which transfers potentially sensitive family images to a third-party service without any explicit consent, privacy notice, retention policy, or access-control guidance. In this context, the content is especially sensitive because it involves personal family photos and chat-derived media, increasing the risk of unauthorized disclosure or policy violations.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The skill instructs sending a generated cart link to a group chat or phone number without an explicit confirmation step or warning about outbound messaging. While lower impact than the photo-upload issue, it can still cause unintended disclosure, spam-like behavior, or sending private purchase links to the wrong recipient if variables are misconfigured.

Static analysis

No suspicious patterns detected.