Back to skill

Security audit

Mini Diary

Security checks for vulnerabilities and agentic risk

Overview

This diary skill is mostly purpose-aligned, but it needs review because it can write or copy sensitive diary data through broadly scoped paths and includes risky NextCloud admin guidance.

Review before installing. Use a dedicated .md diary file, do not point DIARY_FILE at shell profiles or other important files, leave NEXTCLOUD_SYNC_DIR unset unless you intentionally want the full diary copied to a sync location, and avoid the sudo/docker/recursive chown and cron examples unless you have verified the exact target paths and understand the system impact.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/add_note.sh:13
Finding

Insufficient Path Validation Allows Arbitrary User-Scoped File Modification and Unsafe NextCloud Copies

Content
View full analysis

Vulnerability Details

File Location: scripts/add_note.sh:13-45, scripts/add_note.sh:54-55, scripts/add_note.sh:135-159, and scripts/add_note.sh:165-179
Vulnerability Type: Improper path validation and arbitrary file write
Risk Level: High

Vulnerable Code

bash
validate_safe_path() {
    local path="$1"
    local purpose="$2"
    
    # Convert to absolute path
    local abs_path=$(realpath -m "$path" 2>/dev/null || echo "$path")
    
    # Security checks
    if [[ "$abs_path" =~ ^/etc/ ]]; then
        echo "❌ Security error: Cannot write to system directory /etc/" >&2
        exit 1
    fi
    
    if [[ "$abs_path" =~ ^/usr/ ]]; then
        echo "❌ Security error: Cannot write to system directory /usr/" >&2
        exit 1
    fi
    
    if [[ "$abs_path" =~ ^/bin/|^/sbin/|^/lib/|^/lib64/ ]]; then
        echo "❌ Security error: Cannot write to system binaries directory" >&2
        exit 1
    fi
    
    # Ensure it's within user's home or current directory
    local user_home="${HOME:-/tmp}"
    if [[ ! "$abs_path" =~ ^$user_home ]] && [[ ! "$abs_path" =~ ^$(pwd) ]]; then
        echo "⚠️  Warning: $purpose path is outside user directory: $abs_path" >&2
        echo "   Only writing to user home or current directory is allowed for safety." >&2
        exit 1
    fi
    
    # Ensure it's a .md file for diary
    if [[ "$purpose" == "diary" ]] && [[ ! "$abs_path" =~ \.md$ ]]; then
        echo "⚠️  Warning: Diary file should have .md extension" >&2
        # Allow but warn
    fi
    
    echo "$abs_path"
}

DEFAULT_DIARY="$HOME/diary.md"
DIARY_FILE="${DIARY_FILE:-$DEFAULT_DIARY}"
DIARY_FILE=$(validate_safe_path "$DIARY_FILE" "diary")

The validated path is subsequently modified without enforcing the Markdown extension:

bash
# Check if diary file exists, create if not
if [ ! -f "$DIARY_FILE" ]; then
    echo "# 📓 
...[truncated 4451 chars]
Remediation
View remediation

Remediation Suggestions

  1. Restrict diary files to a dedicated canonical directory, such as $HOME/.local/share/mini-diary/, rather than permitting every file below the home directory.
  2. Canonicalize both the target and its parent directory. For a new file, resolve the parent with realpath and then append a validated basename.
  3. Compare canonical paths using path-component-aware string logic rather than regular expressions. For example, accept only the exact root or paths beginning with "$allowed_root/".
  4. Reject diary paths that do not end in .md; do not merely warn.
  5. Reject symbolic links for diary files and synchronization destinations, or explicitly resolve them and validate the resolved destination.
  6. Validate NEXTCLOUD_SYNC_DIR against a separately configured, canonical synchronization root.
  7. Write new files atomically with restrictive permissions and avoid following links. Where supported, use secure file-descriptor operations with no-follow semantics.
  8. Reject control characters, including carriage returns and newlines, in note input if each invocation is intended to create one Markdown list item.
  9. Add tests for sibling-prefix paths, regex metacharacters in HOME, non-Markdown targets, multiline note input, and symlinked NextCloud destinations.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/search_diary.sh:75
Finding

User-Controlled Search Terms Are Interpreted as grep Options

Content
View full analysis

Vulnerability Details

File Location: scripts/search_diary.sh:75-92 and scripts/search_diary.sh:121-138
Vulnerability Type: Argument and option injection
Risk Level: Medium

Vulnerable Code

bash
search_by_tag() {
    local tag="$1"
    echo "🔍 Searching for tag: $tag"
    echo "======================"
    
    grep -n "$tag" "$DIARY_FILE" | while IFS=: read -r line_num content; do
        # Get date context
        local date_line=$(grep -B10 ":$line_num:" <(cat -n "$DIARY_FILE") | grep "## 📅" | tail -1)
        if [ -n "$date_line" ]; then
            local date_info=$(echo "$date_line" | sed 's/.*## 📅 //')
            echo "📅 $date_info"
        fi
        echo "📝 $content"
        echo "---"
    done
    
    local count=$(grep -c "$tag" "$DIARY_FILE" 2>/dev/null || echo 0)
    echo "📊 Found $count notes with tag: $tag"
}
bash
search_in_content() {
    local query="$1"
    echo "🔍 Searching for: \"$query\""
    echo "======================"
    
    grep -i -n "$query" "$DIARY_FILE" | while IFS=: read -r line_num content; do
        # Get date context
        local date_line=$(grep -B10 ":$line_num:" <(cat -n "$DIARY_FILE") | grep "## 📅" | tail -1)
        if [ -n "$date_line" ]; then
            local date_info=$(echo "$date_line" | sed 's/.*## 📅 //')
            echo "📅 $date_info"
        fi
        echo "📝 $content"
        echo "---"
    done
    
    local count=$(grep -i -c "$query" "$DIARY_FILE" 2>/dev/null || echo 0)
    echo "📊 Found $count notes containing: \"$query\""
}

Technical Analysis

Shell quoting prevents word splitting and shell metacharacter execution, but it does not stop a value beginning with - from being interpreted as a command-line option by grep. The calls omit the conventional -- end-of-options delimiter.

Consequently, a crafted tag or content query can change grep behavi ...[truncated 1507 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add an explicit end-of-options delimiter to every invocation that accepts user input:
    bash
    grep -n -- "$tag" "$DIARY_FILE"
    grep -c -- "$tag" "$DIARY_FILE"
    grep -i -n -- "$query" "$DIARY_FILE"
    grep -i -c -- "$query" "$DIARY_FILE"
    
  2. Use fixed-string matching when regular expressions are not an intended feature:
    bash
    grep -F -n -- "$tag" "$DIARY_FILE"
    grep -F -i -n -- "$query" "$DIARY_FILE"
    
  3. Apply the same -- convention consistently to all command invocations receiving variable data.
  4. Add regression tests with values such as -n, -e, -fFILE, --help, and strings containing regular-expression metacharacters.
  5. Consider imposing a reasonable maximum search-term length to limit accidental or malicious resource consumption.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description presents a broader diary application with AI assistance, automatic tagging, and optional cloud synchronization. The supplied code is only a search utility over an existing local diary file. It validates the path, reads the file, searches by tag/date/content, computes simple tag statistics, and lists tags. There is no journaling interface, no note creation or modification, no AI behavior, no tagging engine, and no network/cloud operations. This is a material description-to-behavior mismatch, even though the code is plausibly related to a diary system.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents an end-user diary application with AI tagging and optional cloud sync. The supplied code chunk does not implement diary features, tagging, syncing, or journaling workflows. Instead, it is a security test harness for shell scripts, focused on validating safe path handling, permission operations, and command hygiene. These behaviors are materially different from the declared primary purpose, so this is a description/behavior mismatch.

Content

No source excerpt is available for this finding.

Instruction Override

High
Category
Prompt Injection
Confidence
70% confidence
Finding

This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Content

Scanner excerpt · docs/usage_guide.md (reported line 260)May include surrounding context.

md
**Solution**: Ensure installation completed and scripts are executable

**Problem**: Tags not appearing
**Solution**: Check note content matches tag rules, enable debug mode

**Problem**: Search returns no results
**Solution**: Verify diary file exists and has content

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding

The skill uses 'shell' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill encourages optional NextCloud sync for diary entries, which may contain sensitive personal or work information, but it does not prominently warn users that enabling sync copies that content to external storage and may expose it through server, admin, backup, or misconfiguration risks. This can lead users to unintentionally disclose private journal data beyond the local machine.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The guide states that diary content is automatically copied and synced to a NextCloud directory but does not clearly warn that journal entries may contain sensitive personal, work, or financial information. Users could enable sync without understanding the privacy, retention, access-control, or multi-device exposure implications, increasing the chance of unintended data disclosure.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
88% confidence
Finding

The documentation instructs users to run privileged ownership-changing commands against NextCloud-managed files. Even though this is operational guidance, normalizing sudo/chown in a diary skill can cause accidental permission damage, broaden access to sensitive diary data, or encourage unsafe copy-paste execution in environments where paths are incorrect.

Content

Scanner excerpt · docs/usage_guide.md (reported line 180)May include surrounding context.

md
ls -la /path/to/nextcloud/diary/diary.md

# Fix ownership (if needed)
sudo chown www-data:www-data /path/to/nextcloud/diary/diary.md

# Docker version
docker exec nextcloud_app chown www-data:www-data /var/www/html/data/.../diary.md

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · docs/usage_guide.md (reported line 227)May include surrounding context.

text

### Custom Tags
Create `~/.mini-diary-tags.json`:
```json
{
  "custom_tags": {

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
90% confidence
Finding

This troubleshooting advice recommends recursive ownership changes with sudo or container-level chown across an entire NextCloud diary directory. Recursive privileged file operations are especially risky because a mistaken path or misunderstanding of deployment layout can alter permissions on large data sets and expose or disrupt synced personal records.

Content

Scanner excerpt · docs/usage_guide.md (reported line 277)May include surrounding context.

Solution:

bash
# Fix ownership
sudo chown -R www-data:www-data /path/to/nextcloud/diary/

# Or for Docker
docker exec nextcloud_app chown -R www-data:www-data /var/www/html/data/.../

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest advertises "cloud sync" functionality but provides no user-facing warning or privacy notice about possible transmission of diary contents to external services. Because this skill handles highly sensitive personal journal data, users may unknowingly expose intimate or work-related information off-device, making the omission materially risky even in metadata.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script’s security claims are inaccurate: it states there is no network access and only safe diary-file writes, yet it optionally copies the diary into a user-controlled NextCloud sync directory via the NEXTCLOUD_SYNC_DIR environment variable. Even though the script does not itself open a network connection, placing sensitive diary contents into a sync folder can trigger unintended cloud exfiltration and weakens user trust in the documented security boundary.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The installer’s comments and security messaging state it only copies files and sets permissions, but it also writes new files into the user’s home directory, including a default diary and config example. Misleading security claims reduce informed consent and can cause users or automation to trust the script more than warranted, especially since self-asserted safety language is a red flag in adversarial review.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/install.sh (reported line 41)May include surrounding context.

sh
if [ -d "$INSTALL_DIR/scripts" ]; then
    for script in "$INSTALL_DIR/scripts/"*.sh; do
        if [ -f "$script" ] && [ -O "$script" ]; then  # -O checks if file is owned by effective user
            chmod 755 "$script"
            echo "  ✓ $(basename "$script") set to 755"
        else
            echo "  ⚠️  Skipping $(basename "$script") - not owned by user"

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.sh (reported line 49)May include surrounding context.

sh
done
fi

# Create default diary file if it doesn't exist
DEFAULT_DIARY="$HOME/diary.md"
if [ ! -f "$DEFAULT_DIARY" ]; then
    echo "📓 Creating default diary file: $DEFAULT_DIARY"

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The header and disclaimer state that the script only reads user diary files, implying access is limited to an actual diary file. In practice, DIARY_FILE is taken from the environment and accepted as any file under HOME or the current directory, so the script can be used to search arbitrary user-accessible files rather than specifically a diary.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The output in list_tags tells users that tags are automatically added based on note content, which describes tagging behavior not implemented anywhere in this file. This is an intent/documentation mismatch because the script is purely read-only search/statistics functionality.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This markdown file includes operational instructions to run docker exec nextcloud_app php occ files:scan [username], which affects a live NextCloud instance and user file indexing. The section labels the step as 'Important' but does not warn users about the command's impact, expected context, or that it should only be run against the intended account/server.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.