Back to skill

Security audit

Multimedia Manager

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent local media manager, but verified web gallery and cleanup weaknesses could expose or delete files beyond what users are told.

Review carefully before installing. Use only a strong IMAGE_VAULT_TOKEN, keep IMAGE_VAULT_HOST on 127.0.0.1, avoid importing untrusted category/tag metadata, do not use cleanup_inbound.py with arbitrary directories, and treat imported GPS/location metadata and original file paths as sensitive until the auth, path validation, XSS, and deletion-scope issues are fixed.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/web_server.py:39
Finding

Authentication Fails Open When the Access Token Is Missing

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/web_server.py:158
Finding

Arbitrary File Disclosure Through Unsafe Path-Prefix Validation

Content
View full analysis
Remediation
View remediation
/file`, load the file path from the trusted database record, and never accept a raw path from the request. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/web_server.py:214
Finding

Stored Cross-Site Scripting Through Unescaped Image Category Metadata

Content
View full analysis
{ const div=document.createElement('div'); div.className='item'; const src=img.thumb_path||img.vault_path; div.innerHTML='' +(img.category?''+img.category+'':'') +''+(img.favorited?'❤️':'🤍')+''; div.onclick=()=>window.open(_a('/api/file?path='+encodeURIComponent(img.vault_path)),'_blank'); grid.appendChild(div); }); ``` ### Technical Analysis The gallery inserts database-controlled metadata directly into an HTML parsing sink: ```javascript ''+img.category+'' ``` The `category` value can be supplied during media import through the CLI and is stored in SQLite without HTML sanitization. When the gallery loads search results, this value is incorporated into `innerHTML`, allowing HTML elements and event-handler attributes to be interpreted by the browser. This is a stored XSS vulnerability because the malicious value persists in the database and executes whenever an authorized user views the affected image in the gallery. The authentication cookie is marked `HttpOnly`, which prevents direct JavaScript reads, but injected code runs in the gallery origin. It can therefore issue authenticated same-origin requests using the victim's cookie. ### Attack Path 1. An attacker or untrusted import workflow assigns crafted HTML to an image category, such as an element with an event handler. 2. The image is imported, and the category is stored in the SQLite database. 3. A user opens the web gallery and performs a search that returns the affected image. 4. The gallery concatenates the category into `div.innerHTML`. 5. The b ...[truncated 758 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/cleanup_inbound.py:11
Finding

Unrestricted User-Selected Directory Can Cause Destructive File Deletion

Content
View full analysis
/inbound`. Every directly contained regular file older than the threshold is permanently unlinked. The default mode performs deletion rather than dry-run, and there is no confirmation prompt. Negative values for `max_age_hours` are also not rejected; these values move the cutoff into the future and can make recently created files eligible for deletion. This behavior can exceed the minimu ...[truncated 1172 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
setup.sh:43
Finding

Unpinned Dependencies Are Installed Into the Active Python Environment

Content
View full analysis
/dev/null || pip install -q Flask Pillow PyYAML echo "✓ Dependencies installed" ``` From `requirements.txt`: ```text Flask>=3.0 Pillow>=10.0 PyYAML>=6.0 ``` ### Technical Analysis The setup script installs packages by name without exact versions or artifact hashes. The requirements file only defines minimum versions, allowing later releases to be installed without review. The command also uses whichever `pip3` or `pip` executable appears first in the current `PATH`, rather than binding installation to the interpreter used to run the application. No virtual environment is created, so packages may be installed into or modify the user's active or global Python environment. Python package installation may execute package build and installation logic. A compromised package index, compromised future release, unsafe custom index configuration, or PATH-manipulated `pip` executable could therefore execute unexpected code during setup. No evidence was found that Flask, Pillow, or PyYAML are typosquatted packages. The risk arises from mutable dependency resolution and missing integrity controls, not from a confirmed malicious dependency. ### Attack Path 1. The user runs `bash setup.sh`. 2. The shell resolves `pip3` or the fallback `pip` from `PATH`. 3. The installer contacts its configured Python package index. 4. Because versions and hashes are not pinned, the resolver selects currently available compatible releases. 5. A compromised release, index response, or substituted `pip` executable executes code during installation. 6. The code runs with the privileges of the user execut ...[truncated 549 chars]
Remediation
View remediation
\ --hash=sha256: ``` ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (39)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/image_db.py (reported line 15)May include surrounding context.

python
def _load_dotenv():
    """Load .env from skill root (one level up from scripts/)."""
    env_path = os.path.join(os.path.dirname(__file__), "..", ".env")
    if not os.path.isfile(env_path):
        return
    with open(env_path) as f:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · setup.sh (reported line 49)May include surrounding context.

sh
def _load_dotenv():
    """Load .env from skill root (one level up from scripts/)."""
    env_path = os.path.join(os.path.dirname(__file__), "..", ".env")
    if not os.path.isfile(env_path):
        return
    with open(env_path) as f:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · setup.sh (reported line 51)May include surrounding context.

sh
def _load_dotenv():
    """Load .env from skill root (one level up from scripts/)."""
    env_path = os.path.join(os.path.dirname(__file__), "..", ".env")
    if not os.path.isfile(env_path):
        return
    with open(env_path) as f:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · setup.sh (reported line 63)May include surrounding context.

sh
def _load_dotenv():
    """Load .env from skill root (one level up from scripts/)."""
    env_path = os.path.join(os.path.dirname(__file__), "..", ".env")
    if not os.path.isfile(env_path):
        return
    with open(env_path) as f:

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The permanent deletion paths remove files from disk and delete database records immediately, with no safety checks, authorization guard, or confirmation mechanism in this layer. If these functions are reachable from an agent action or exposed API, a mistaken or malicious invocation could irreversibly destroy user data.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Loading a parent .env file is credential-access relevant because .env files commonly contain API keys, tokens, and database secrets, and this code imports them wholesale into the running process. In a reusable skill context, this broad secret ingestion exceeds least privilege and increases the blast radius if the app, its logs, or dependent modules are compromised.

Content

Scanner excerpt · scripts/web_server.py (reported line 14)May include surrounding context.

python
sys.path.insert(0, os.path.dirname(__file__))

def _load_dotenv():
    env_path = os.path.join(os.path.dirname(__file__), "..", ".env")
    if not os.path.isfile(env_path):
        return
    with open(env_path) as f:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · config.example.yaml (reported line 9)May include surrounding context.

yaml
# What this script does:
#   1. Checks Python 3.9+ and ffmpeg availability
#   2. Installs 3 Python packages: Flask, Pillow, PyYAML
#   3. Creates .env with a random access token (if not exists)
#   4. Creates ~/.image-vault directory for local storage
#   5. Initializes the SQLite database
#

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/image_db.py (reported line 14)May include surrounding context.

python
# What this script does:
#   1. Checks Python 3.9+ and ffmpeg availability
#   2. Installs 3 Python packages: Flask, Pillow, PyYAML
#   3. Creates .env with a random access token (if not exists)
#   4. Creates ~/.image-vault directory for local storage
#   5. Initializes the SQLite database
#

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · setup.sh (reported line 7)May include surrounding context.

sh
# What this script does:
#   1. Checks Python 3.9+ and ffmpeg availability
#   2. Installs 3 Python packages: Flask, Pillow, PyYAML
#   3. Creates .env with a random access token (if not exists)
#   4. Creates ~/.image-vault directory for local storage
#   5. Initializes the SQLite database
#

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · setup.sh (reported line 48)May include surrounding context.

sh
# What this script does:
#   1. Checks Python 3.9+ and ffmpeg availability
#   2. Installs 3 Python packages: Flask, Pillow, PyYAML
#   3. Creates .env with a random access token (if not exists)
#   4. Creates ~/.image-vault directory for local storage
#   5. Initializes the SQLite database
#

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · setup.sh (reported line 59)May include surrounding context.

sh
# What this script does:
#   1. Checks Python 3.9+ and ffmpeg availability
#   2. Installs 3 Python packages: Flask, Pillow, PyYAML
#   3. Creates .env with a random access token (if not exists)
#   4. Creates ~/.image-vault directory for local storage
#   5. Initializes the SQLite database
#

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/web_server.py (reported line 65)May include surrounding context.

python
# What this script does:
#   1. Checks Python 3.9+ and ffmpeg availability
#   2. Installs 3 Python packages: Flask, Pillow, PyYAML
#   3. Creates .env with a random access token (if not exists)
#   4. Creates ~/.image-vault directory for local storage
#   5. Initializes the SQLite database
#

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · setup.sh (reported line 7)May include surrounding context.

sh
# What this script does:
#   1. Checks Python 3.9+ and ffmpeg availability
#   2. Installs 3 Python packages: Flask, Pillow, PyYAML
#   3. Creates .env with a random access token (if not exists)
#   4. Creates ~/.image-vault directory for local storage
#   5. Initializes the SQLite database
#

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

This line prints the access token directly to stdout, which is a genuine secret disclosure. Anyone with access to terminal history, logs, remote session recordings, or shared output can recover the token and use it to access the gallery.

Content

Scanner excerpt · setup.sh (reported line 56)May include surrounding context.

sh
IMAGE_VAULT_TOKEN=$TOKEN
# IMAGE_VAULT_DIR=$DEFAULT_VAULT
EOF
  echo "✓ Created .env with auto-generated token: $TOKEN"
  echo "  ⚠ Save this token — you'll need it to access the gallery"
else
  echo "✓ .env already exists"

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 · SKILL.md (reported line 40)May include surrounding context.

md
| Resource | Why | Scope |
|----------|-----|-------|
| **File system** | Read/write images to `~/.image-vault` | Only `IMAGE_VAULT_DIR` directory |
| **SQLite database** | Store image metadata (no images in DB) | `~/.image-vault/image_vault.db` |
| **Local HTTP server** | Web gallery UI on `127.0.0.1` | Localhost only, token-protected |
| **Python packages** | Flask, Pillow, PyYAML (via `pip`) | Standard packages |

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The theme names and album descriptions are hardcoded in Chinese, so generated album names and metadata will use a specific language regardless of user preference. This is a natural-language locale policy issue because the file does not provide opt-in, configuration, or documented justification for enforcing that locale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

This code creates albums and adds images to them, which is a write operation affecting user data organization. While the script supports a --dry-run mode, the non-dry-run path performs changes without an in-code confirmation prompt or user-facing disclosure at the point of action beyond the final 'Created' output after changes are already made.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Multiple comments and docstrings in this file are written only in Chinese, while other parts of the file are in English, indicating a mixed but partially fixed language presentation. The skill does not offer any language choice or document that it is intentionally region/language-specific, which can violate language/locale policy expectations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code reads GPS coordinates from image EXIF data and later the schema includes latitude, longitude, and location_name fields, which is privacy-sensitive behavior. While there are internal docstrings, there is no visible user disclosure, confirmation prompt, or user-facing logging in this file warning that location metadata may be collected and stored.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/image_import.py (reported line 105)May include surrounding context.

python
"ffprobe", "-v", "quiet", "-print_format", "json",
            "-show_format", "-show_streams", filepath
        ]
        out = subprocess.check_output(cmd, timeout=15, text=True)
        data = json.loads(out)
        duration = float(data.get("format", {}).get("duration", 0))
        width, height = None, None

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/image_import.py (reported line 129)May include surrounding context.

python
"-i", video_path, "-frames:v", "1",
            "-q:v", "2", output_path
        ]
        subprocess.run(cmd, capture_output=True, timeout=15)
        if os.path.isfile(output_path) and os.path.getsize(output_path) > 0:
            return output_path
    except Exception as e:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code can perform an irreversible operation by moving the user's file, which removes it from the original location when copy is false. While the CLI flag name --move hints at this behavior, the function itself has no confirmation prompt or explicit user-facing warning at the point of execution, and this is a safety-relevant file operation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The importer automatically extracts EXIF date and GPS coordinates from user media and persists them without any disclosure, consent gate, or minimization. In a media-vault context this is meaningfully sensitive because location and timestamp metadata can reveal home addresses, routines, travel history, or identities, and users may not realize importing a photo also stores hidden metadata.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The server automatically reads a parent-directory .env file and imports every key into the process environment without validating origin or scope. In a skill/plugin context, this can unintentionally ingest secrets belonging to the host environment or adjacent projects, expanding the skill's access to credentials and making later misuse or leakage more likely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Lines L143-L146 expose an irreversible image deletion operation, but this file provides no confirmation prompt, warning message, comment, or docstring disclosing that the action deletes user data. Under the code-file criteria, destructive operations should have some visible user disclosure unless clearly documented as the skill's stated purpose, which is not evident here.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.