Back to skill

Security audit

Mixtiles Monthly

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate monthly photo-ordering purpose, but its script can collect photos outside the intended month and may attach the wrong local file for later processing or upload.

Review this skill before unattended use. It should be limited to a clearly consented WhatsApp group, fixed to enforce both start and end dates for the target month, and changed to reject ambiguous downloads instead of selecting the newest local file. Users should also be comfortable with selected private photos being uploaded to Cloudinary and should clean up the local photo queue when done.

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

Warning
Location
scripts/collect-photos.sh:31
Finding
Photo Collection Exceeds the Declared Monthly Date Range## Vulnerability Details **File Location**: `scripts/collect-photos.sh:31-36` and `SKILL.md:31-39` **Vulnerability Type**: Excessive collection of private media caused by an incomplete date constraint **Risk Level**: Medium ### Vulnerable Code ```bash # 1. Search for image messages in the group after the given date echo "[collect] Searching for images in $GROUP_JID after $AFTER_DATE..." >&2 MESSAGES_JSON=$(wacli messages search "*" \ --chat "$GROUP_JID" \ --type image \ --after "$AFTER_DATE" \ --limit 100 \ --json 2>/dev/null) ``` The documented invocation only supplies the first day of the previous month: ```bash YEAR_MONTH=$(date -v-1m +%Y-%m) AFTER_DATE="${YEAR_MONTH}-01" OUTPUT_DIR=~/mixtiles-queue/${YEAR_MONTH} bash <skill-dir>/scripts/collect-photos.sh "$MIXTILES_GROUP_JID" "$AFTER_DATE" "$OUTPUT_DIR" ``` ### Technical Analysis The Skill claims to collect photos from the previous month, but the search applies only a lower date bound through `--after`. It does not apply an upper bound corresponding to the first day of the current month. If the pipeline is run after the month changes, the query can return both previous-month images and images posted during the current month. Those additional images may then be downloaded, analyzed by the Agent's vision capability, and selected for upload to Cloudinary through the downstream Mixtiles cart Skill. This is a data-minimization and scope-enforcement flaw. The affected data consists of private images and associated WhatsApp metadata from the configured group. ### Attack Path 1. The monthly pipeline calculates only the first day of the previous month. 2. The collection script searches for every image after that date, without an upper date limit. 3. Group members post private images during the current month. 4. The unrestricted query includes those current-month images among its results. 5. The script downloads the imag ...[truncated 671 chars]
Remediation
## Remediation Suggestions Calculate both the first day of the previous month and the first day of the current month, then pass both bounds to the collection script. Use a supported upper-bound option such as `--before` when invoking `wacli`. In addition, independently parse and validate every returned message timestamp before downloading it. Reject entries whose timestamp does not satisfy the intended half-open interval: ```text previous_month_start <= timestamp < current_month_start ``` The validation should use a consistent timezone and fail closed when a timestamp is absent or malformed. This prevents unexpected `wacli` behavior from expanding the collection scope.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/collect-photos.sh:68
Finding
Ambiguous Download Fallback Can Select and Upload an Unrelated Local File## Vulnerability Details **File Location**: `scripts/collect-photos.sh:68-71` **Vulnerability Type**: Unsafe file association and stale-file reuse **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 ``` The selected path is subsequently accepted based only on whether it is a regular file: ```bash if [ -n "$FILEPATH" ] && [ -f "$FILEPATH" ]; then DOWNLOADED=$((DOWNLOADED + 1)) echo "[collect] Downloaded: $FILEPATH" >&2 echo "{\"id\":\"$MSG_ID\",\"sender\":\"$SENDER\",\"timestamp\":\"$TIMESTAMP\",\"filepath\":\"$FILEPATH\"}" else echo "[collect] No file found for $MSG_ID" >&2 FAILED=$((FAILED + 1)) fi ``` ### Technical Analysis The fallback comment states that it checks for a new file, but the implementation merely selects the most recently modified directory entry. It does not record the directory contents before download, verify that the selected file was created or modified by the current `wacli` operation, confirm that it corresponds to the current message, or validate that it is an image. If `wacli media download` succeeds but returns output without a recognized path field, any pre-existing file with the newest modification time can be inserted into the manifest. The downstream workflow treats manifest paths as downloaded photos and may inspect and upload them to Cloudinary. The output directory is persistent and month-based, so files left by earlier runs can also be selected accidentally. If another local process or user can write to the directory, the issue can be deliberately exploited by placing a chosen file there. ### Attack Path 1. A stale file already exists in the output directory, or a local actor places a chosen ...[truncated 1125 chars]
Remediation
## Remediation Suggestions Remove the most-recent-file fallback and require `wacli` to return a valid, unambiguous path. Treat a missing path as a failed download. If compatibility requires a fallback: 1. Use a newly created, permission-restricted directory for each run. 2. Snapshot directory entries before invoking `wacli`. 3. Compare pre-download and post-download directory states. 4. Accept exactly one newly created regular file. 5. Resolve the path with `realpath` and verify that it remains beneath the expected output directory. 6. Reject symbolic links and non-regular files. 7. Validate the file's MIME type and image structure before adding it to the manifest. 8. Reject ambiguous results rather than selecting a file based on modification time. 9. Clean up or archive the per-run directory after processing. Where supported, direct each download to a unique filename derived from a safely encoded message identifier instead of inferring the downloaded path.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/collect-photos.sh:78
Finding
Unescaped Metadata Is Interpolated Directly into the JSON Manifest## Vulnerability Details **File Location**: `scripts/collect-photos.sh:78` **Vulnerability Type**: Improper JSON output encoding **Risk Level**: Low ### Vulnerable Code ```bash echo "{\"id\":\"$MSG_ID\",\"sender\":\"$SENDER\",\"timestamp\":\"$TIMESTAMP\",\"filepath\":\"$FILEPATH\"}" ``` ### Technical Analysis The script builds JSON through shell string interpolation rather than a JSON serializer. `MSG_ID`, `SENDER`, and `TIMESTAMP` originate from WhatsApp message data, while `FILEPATH` originates from command output or directory contents. JSON-significant characters such as double quotes, backslashes, newlines, carriage returns, tabs, or other control characters are not escaped. A value containing such characters can make the emitted object invalid or alter its apparent JSON structure. The resulting lines are passed to `jq -s '.'`. Malformed JSON will normally cause `jq` to fail and, because the script uses `set -euo pipefail`, can terminate the collection operation. Carefully formed metadata may also manipulate fields represented in a serialized object if downstream parsing behavior changes. The values are quoted when used by the shell, so this finding does not by itself establish shell-command execution. ### Attack Path 1. A message or download result supplies a metadata value containing JSON metacharacters or control characters. 2. The script interpolates the value directly between JSON quotation marks. 3. The generated line becomes malformed or contains attacker-influenced JSON structure. 4. The final `jq -s '.'` operation fails, terminating photo collection, or downstream consumers receive corrupted or misleading manifest data. 5. The monthly workflow is interrupted or processes incorrectly attributed metadata. ### Impact Assessment No additional system privileges are obtained, and direct command execution is not demonstrated. The primary impact is availability and integrity: a crafted or unexpected value c ...[truncated 230 chars]
Remediation
## Remediation Suggestions Generate each manifest entry with `jq` so every value is correctly encoded: ```bash jq -n \ --arg id "$MSG_ID" \ --arg sender "$SENDER" \ --arg timestamp "$TIMESTAMP" \ --arg filepath "$FILEPATH" \ '{id: $id, sender: $sender, timestamp: $timestamp, filepath: $filepath}' ``` Continue aggregating the serialized objects with `jq -s '.'`. Validate expected field formats before serialization, including the message identifier, timestamp, and path. Treat missing or structurally invalid required values as explicit per-message failures instead of emitting partial or malformed records.
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 (2)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The declared description describes an end-to-end monthly Mixtiles workflow: collecting photos, selecting the best ones with vision, creating a Mixtiles cart link, and sending it. The supplied code implements only the collection step: it queries WhatsApp image messages after a date, downloads media, and emits a manifest. While photo collection from a WhatsApp group is consistent with part of the description, the actual code lacks the other core stated behaviors, so the description materially overstates what this code chunk does.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill collects photos from a WhatsApp group and uploads selected images to Cloudinary, but the description does not clearly disclose these data flows or the third-party transfer. That creates a meaningful privacy risk because users may invoke the skill without understanding that private family images are being processed and sent outside WhatsApp to an external service.