Back to skill

Security audit

Medication Reminder

Security checks for vulnerabilities and agentic risk

Overview

This is a simple local medication logger, but it stores sensitive health records without enforced privacy protections and has reliability issues that can corrupt or misrepresent medication data.

Review before installing. Use only on a private machine/account, assume medication records will be stored in plaintext at ~/.local/share/medication-reminder/, and do not rely on it for real due-dose reminders until permissions, input handling, deletion controls, and schedule logic are fixed.

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/script.sh:6
Finding

Sensitive Medication Records Are Stored Without Enforced Access Restrictions

Content
View full analysis
> $DATA_DIR/meds.jsonl ``` ```bash echo '{"med":"'$2'","taken":"'$(date +%Y-%m-%d_%H:%M)'"}' >> $DATA_DIR/intake.jsonl ``` ### Technical Analysis The Skill stores medication names, doses, schedules, and intake timestamps. This information constitutes sensitive health-related data. Neither the storage directory nor the resulting JSONL files are assigned explicit restrictive permissions. The effective permissions therefore depend entirely on the invoking process's `umask`. Under a commonly used `022` umask, the directory may be created with mode `755` and files with mode `644`, potentially making the records readable by other accounts on the same system where parent-directory traversal is permitted. The destination path expansions are also unquoted. Although the fixed directory name contains no spaces, quoting remains necessary to handle unusual values of `$HOME` safely and consistently. ### Attack Path 1. A user invokes the Skill to add a medication or log an intake event. 2. The script creates the data directory and JSONL files according to the caller's current `umask`. 3. On a multi-user system with permissive effective modes, another local account traverses the user's accessible home-directory path. 4. The account reads `meds.jsonl` or `intake.jsonl`. 5. Medication names, doses, frequencies, and intake timestamps are disclosed. This path requires local filesystem access and sufficiently permissive parent-directory permissions. The script does not itself ...[truncated 416 chars]
Remediation
View remediation
> "$DATA_DIR/meds.jsonl" ``` 4. Explicitly set existing and newly created record files to mode `600`. 5. Refuse to use the storage directory if it is a symbolic link or is owned by a different user. 6. Consider encrypting the records at rest if the intended threat model includes privileged backup systems or offline disk access. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/script.sh:92
Finding

Unescaped User Input Corrupts JSONL Records and Can Manipulate Terminal Output

Content
View full analysis
" echo '{"med":"'$2'","dose":"'$3'","freq":"'$4'","ts":"'$(date +%s)'"}' >> $DATA_DIR/meds.jsonl && echo 'Added $2' } cmd_list() { cat $DATA_DIR/meds.jsonl 2>/dev/null | tail -10 } cmd_take() { local med="${2:-}" [ -z "$med" ] && die "Usage: $SCRIPT_NAME take " echo '{"med":"'$2'","taken":"'$(date +%Y-%m-%d_%H:%M)'"}' >> $DATA_DIR/intake.jsonl && echo 'Logged: $2' } ``` The history command also emits stored data without sanitization: ```bash cmd_history() { local days="${2:-}" [ -z "$days" ] && die "Usage: $SCRIPT_NAME history " tail -${2:-20} $DATA_DIR/intake.jsonl 2>/dev/null } ``` ### Technical Analysis User-controlled medication, dose, and frequency values are concatenated directly into JSON text rather than being passed through a JSON serializer. Characters such as double quotes and backslashes can therefore terminate or alter expected JSON string values, producing malformed records or injecting additional JSON fields. Because the expansions are unquoted, shell word splitting and pathname expansion also affect the resulting data. While shell metacharacters contained in parameter values are not automatically re-evaluated as shell syntax, whitespace can be normalized and wildcard values can expand to matching pathnames. Consequently, the stored value may differ substantially from the supplied value. The `list` and `history` commands print persisted values directly to the terminal. An input containing ANSI terminal control characters can later alter colors, move the cursor, clear visibl ...[truncated 1346 chars]
Remediation
View remediation
> "$DATA_DIR/meds.jsonl" ``` 2. Quote all parameter and pathname expansions. 3. Reject NUL bytes and terminal control characters in medication-related fields. 4. Apply length limits and define an explicit accepted-character policy where practical. 5. When displaying stored values in an interactive terminal, remove or visibly encode non-printable control characters. 6. Validate existing JSONL records before treating them as medication data. 7. Replace `cat file | tail` with a directly quoted invocation: ```bash tail -n 10 -- "$DATA_DIR/meds.jsonl" ``` ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/script.sh:92
Finding

Incorrect Positional Argument Handling Breaks Core Medication Commands

Content
View full analysis
" echo '{"med":"'$2'","dose":"'$3'","freq":"'$4'","ts":"'$(date +%s)'"}' >> $DATA_DIR/meds.jsonl && echo 'Added $2' } ``` ```bash cmd_take() { local med="${2:-}" [ -z "$med" ] && die "Usage: $SCRIPT_NAME take " echo '{"med":"'$2'","taken":"'$(date +%Y-%m-%d_%H:%M)'"}' >> $DATA_DIR/intake.jsonl && echo 'Logged: $2' } cmd_history() { local days="${2:-}" [ -z "$days" ] && die "Usage: $SCRIPT_NAME history " tail -${2:-20} $DATA_DIR/intake.jsonl 2>/dev/null } ``` However, the dispatcher removes the command name before calling each handler: ```bash main() { local cmd="${1:-help}" case "$cmd" in add) shift; cmd_add "$@" ;; list) shift; cmd_list "$@" ;; take) shift; cmd_take "$@" ;; history) shift; cmd_history "$@" ;; schedule) shift; cmd_schedule "$@" ;; due) shift; cmd_due "$@" ;; help) cmd_help ;; version) cmd_version ;; *) die "Unknown: $cmd" ;; esac } ``` ### Technical Analysis After `main` executes `shift`, the first command argument becomes `$1` inside the handler. The handlers incorrectly begin reading from `$2`. For a documented command such as: ```bash scripts/script.sh add aspirin 100mg daily ``` the handler receives: ```text $1 = aspirin $2 = 100mg $3 = daily $4 = unset ``` It therefore treats `100mg` as the medication, `daily` as the dose, and attempts to access an unset `$4`. Because the script enables `set -u`, this can terminate execution. Likewise, the documented one-argument forms of ` ...[truncated 1461 chars]
Remediation
View remediation
" local med="$1" local dose="$2" local frequency="$3" # Serialize safely. } ``` 2. Apply equivalent corrections to `take` and `history`. 3. Validate exact argument counts before accessing positional parameters. 4. Validate history input as a bounded positive integer: ```bash [[ "$days" =~ ^[1-9][0-9]*$ ]] || die "Days must be a positive integer" (( days <= 3650 )) || die "Days exceeds the supported limit" ``` 5. Pass the validated value as an argument rather than constructing an option through concatenation: ```bash tail -n "$days" -- "$DATA_DIR/intake.jsonl" ``` 6. Add automated tests covering every documented command with valid, missing, excessive, and malformed arguments. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
80% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

Scanner excerpt · scripts/script.sh (reported line 9)May include surrounding context.

sh
DATA_DIR="$HOME/.local/share/medication-reminder"
mkdir -p "$DATA_DIR"

#
#
#
#

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This script stores sensitive medication names, doses, frequencies, and intake history in predictable plaintext files under the user's home directory without any warning, permission hardening, or privacy controls. In the context of a medication-management skill, this is health-related data, so silent local persistence increases privacy risk if the host is shared, backed up, or inspected by other local processes/users.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest says the skill tracks medications with dosing schedules and intake history, implying actual schedule management and due-medication calculation. In code, schedule and due only print static placeholder text, while the implemented behavior is limited to appending medication and intake records and showing recent entries.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.