Back to skill

Security audit

PromptVault Team Prompt Library

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local prompt library, but shared imports can create unsafe HTML that may expose vault contents in the browser.

Review or fix the HTML-generation bug before using team imports from anyone you do not fully trust. Treat vaults, exports, backups, and generated HTML as sensitive plaintext; redact secrets and internal instructions before sharing or sending prompt text to external APIs, and restrict file access with normal filesystem or Git permissions.

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

T09 · Insecure Skill Coding Practices

Error
Location
prompt_browse.py:366
Finding
Stored JavaScript Injection Through Unvalidated Imported Prompt IDs<![CDATA[ ## Vulnerability Details **File Location**: `prompt_sync.py:119-130` and `prompt_browse.py:329-366` **Vulnerability Type**: Stored JavaScript injection in generated HTML **Risk Level**: High ### Vulnerable Code The import process accepts an attacker-controlled prompt ID without validating its format or type: ```python # prompt_sync.py:119-130 with open(import_path, 'r', encoding='utf-8') as f: import_data = json.load(f) existing_ids = {p['id']: i for i, p in enumerate(vault['prompts'])} stats = { 'total': len(import_data.get('prompts', [])), 'added': 0, 'skipped': 0, 'replaced': 0, 'errors': [] } for prompt in import_data.get('prompts', []): prompt_id = prompt.get('id') ``` The imported ID is subsequently embedded directly into an inline JavaScript event handler: ```python # prompt_browse.py:329-366 for p in by_category[cat]: prompt_id = p.get('id', '') name = p.get('name', 'Untitled') text = p.get('text', '') rating = p.get('rating', 0) stars = '⭐' * rating if rating else '☆☆☆☆☆' tags = p.get('tags', []) author = p.get('author', 'Unknown') usage_count = p.get('usage_count', 0) notes = p.get('notes', '') models = p.get('model_compat', '') tags_html = ''.join(f'<span class="tag">{html.escape(tag)}</span>' for tag in tags) html_content += f""" <div class="prompt-card" data-tags="{html.escape(','.join(tags))}"> <div class="prompt-header"> <div class="prompt-name">{html.escape(name)}</div> <div class="prompt-rating">{stars}</div> </div> <div class="prompt-meta"> <span>ID: <code>{html.escape(prompt_id)}</code></span> <span>By: {html.escape(author)}</span> <span>Used: {usage_count} times</span> """ if models: html_content += f' <span>Models: {html.escape(models)}</span>\n' html_content += ' </div>\n' if tags: ...[truncated 3037 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Strictly validate imported IDs** Enforce the same format used by the native ID generator: ```python import re if not isinstance(prompt_id, str) or not re.fullmatch(r'[0-9a-f]{12}', prompt_id): stats['errors'].append("Prompt has an invalid ID") continue ``` 2. **Remove inline JavaScript event handlers** Store identifiers in an escaped data attribute: ```python html_content += ( f'<button class="copy-btn" ' f'data-prompt-id="{html.escape(prompt_id, quote=True)}">' f'Copy to Clipboard</button>\n' ) ``` Register the event handler separately: ```javascript document.querySelectorAll('.copy-btn').forEach(button => { button.addEventListener('click', event => { copyPrompt(event.currentTarget.dataset.promptId, event.currentTarget); }); }); ``` 3. **Avoid searching IDs through unrestricted text content** Associate each card with an exact, validated `data-prompt-id` value and select the matching card by that value. This prevents ambiguous matches and separates data from executable code. 4. **Validate the complete import schema** Before persistence, verify that each prompt is an object and that fields such as `id`, `name`, `text`, `category`, `tags`, `rating`, and `usage_count` have expected types and reasonable size limits. 5. **Apply a restrictive Content Security Policy** Generated pages should prohibit inline scripts and unnecessary network access. Move JavaScript into a separate local file or use a nonce/hash-based policy if a standalone file is required. CSP should be treated as defense in depth rather than a replacement for safe construction. 6. **Add regression tests** Test imported IDs containing single quotes, double quotes, angle brackets, backslashes, newlines, and JavaScript syntax. Verify that generated HTML contains no executable attacker-controlled content and that legitimate copy functiona ...[truncated 29 chars]
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (20)

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
**Features:**
- Search bar (live filtering)
- Category filters
- Click to copy prompt to clipboard
- No server needed (open in browser)
- Works offline
- Share with team (just send the HTML file)
Confidence
86% confidence
Finding
The HTML browse feature explicitly advertises one-click copying of full prompt contents to the clipboard and sharing the HTML file with a team. In a prompt vault context, this materially increases the risk of easy extraction and redistribution of sensitive prompts, internal instructions, or embedded secrets, especially when combined with static offline sharing.

Hidden Instructions

High
Category
Prompt Injection
Content
---
name: "PromptVault Team Prompt Library"
description: "Organize, rate, and share prompts with your team. Never lose a great prompt again. Centralized prompt management with search, tags, and ratings."
author: "@TheShadowRose"
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
---
name: "PromptVault Team Prompt Library"
description: "Organize, rate, and share prompts with your team. Never lose a great prompt again. Centralized prompt management with search, tags, and ratings."
author: "@TheShadowRose"
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
**Features:**
- Search bar (live filtering)
- Category filters
- Click to copy prompt to clipboard
- No server needed (open in browser)
- Works offline
- Share with team (just send the HTML file)
Confidence
80% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
self.vault['prompts'].append(prompt)
        self._save_vault()
        
        return prompt_id
    
    def get_prompt(self, prompt_id):
        """Get a prompt by ID"""
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
self.vault['prompts'].append(prompt)
        self._save_vault()
        
        return prompt_id
    
    def get_prompt(self, prompt_id):
        """Get a prompt by ID"""
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
self.vault['prompts'].append(prompt)
        self._save_vault()
        
        return prompt_id
    
    def get_prompt(self, prompt_id):
        """Get a prompt by ID"""
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The README strongly promotes team sharing and static HTML export of prompts, including ratings, notes, and changelog-related data, but does not prominently warn that prompts often contain sensitive internal instructions, credentials, customer data, or proprietary workflows. In this context, encouraging easy sharing and browser-friendly export increases the chance of accidental disclosure to teammates, shared drives, or downstream recipients.

External Transmission

Medium
Category
Data Exfiltration
Content
TEXT=$(python prompt_vault.py get $PROMPT_ID --use | grep -A 999 "text:" | tail -n +2)

# Use with AI API
curl -X POST https://api.example.com/chat \
  -d "{\"prompt\": \"$TEXT\"}"
```
Confidence
90% confidence
Finding
The automation example shows extracting prompt text from the local vault and sending it directly to an external API with curl. Since stored prompts may include confidential instructions, internal procedures, or embedded secrets, this normalizes exfiltration of vault contents to third-party services without any caution about data sensitivity, approval, or sanitization.

External Transmission

Medium
Category
Data Exfiltration
Content
TEXT=$(python prompt_vault.py get $PROMPT_ID --use | grep -A 999 "text:" | tail -n +2)

# Use with AI API
curl -X POST https://api.example.com/chat \
  -d "{\"prompt\": \"$TEXT\"}"
```
Confidence
90% confidence
Finding
The automation example shows extracting prompt text from the local vault and sending it directly to an external API with curl. Since stored prompts may include confidential instructions, internal procedures, or embedded secrets, this normalizes exfiltration of vault contents to third-party services without any caution about data sensitivity, approval, or sanitization.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill heavily promotes export, import, HTML generation, and team sharing of prompt libraries without a clear warning that prompt text, notes, ratings, and changelog entries may contain secrets, proprietary workflows, customer data, or internal policies. In this context, users are encouraged to distribute artifacts broadly, which increases the risk of accidental data exposure even if no exfiltration is automatic.

External Transmission

Medium
Category
Data Exfiltration
Content
TEXT=$(python prompt_vault.py get $PROMPT_ID --use | grep -A 999 "text:" | tail -n +2)

# Use with AI API
curl -X POST https://api.example.com/chat \
  -d "{\"prompt\": \"$TEXT\"}"
```
Confidence
94% confidence
Finding
The automation example retrieves stored prompt text and posts it to an external API with curl, normalizing a workflow that transmits potentially sensitive prompt contents off-host. Because this skill is specifically about centralizing team prompts, the exported text may include confidential instructions, internal data handling guidance, or embedded secrets, making external transmission riskier in context.

External Transmission

Medium
Category
Data Exfiltration
Content
TEXT=$(python prompt_vault.py get $PROMPT_ID --use | grep -A 999 "text:" | tail -n +2)

# Use with AI API
curl -X POST https://api.example.com/chat \
  -d "{\"prompt\": \"$TEXT\"}"
```
Confidence
94% confidence
Finding
The automation example retrieves stored prompt text and posts it to an external API with curl, normalizing a workflow that transmits potentially sensitive prompt contents off-host. Because this skill is specifically about centralizing team prompts, the exported text may include confidential instructions, internal data handling guidance, or embedded secrets, making external transmission riskier in context.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code creates parent directories and writes the generated HTML file containing prompt names, text, notes, and metadata to the filesystem. While the script prints success afterward, there is no prior warning in comments, docstrings, or CLI help that running it will persist vault contents to disk, which may matter if the vault contains sensitive prompts or notes.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The import path performs safety-relevant file modifications: it creates parent directories, renames any existing vault to a backup, and writes a new vault file. Although the script prints a completion message afterward, there is no confirmation prompt or explicit warning at the point of action that the destination file will be replaced/modified.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
# Delete command
    delete_parser = subparsers.add_parser('delete', help='Delete a prompt')
    delete_parser.add_argument('id', help='Prompt ID')
    delete_parser.add_argument('--confirm', action='store_true', help='Skip confirmation')
    
    # Stats command
    stats_parser = subparsers.add_parser('stats', help='Show vault statistics')
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Scope Creep

Low
Category
Excessive Agency
Content
**USE AT YOUR OWN RISK.**

- The author(s) are NOT liable for any damages, losses, or consequences arising from 
  the use or misuse of this software — including but not limited to financial loss, 
  data loss, security breaches, business interruption, or any indirect/consequential damages.
- This software does NOT constitute financial, legal, trading, or professional advice.
- Users are solely responsible for evaluating whether this software is suitable for
Confidence
70% confidence
Finding
Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Scope Creep

Low
Category
Excessive Agency
Content
**USE AT YOUR OWN RISK.**

- The author(s) are NOT liable for any damages, losses, or consequences arising from 
  the use or misuse of this software — including but not limited to financial loss, 
  data loss, security breaches, business interruption, or any indirect/consequential damages.
- This software does NOT constitute financial, legal, trading, or professional advice.
- Users are solely responsible for evaluating whether this software is suitable for
Confidence
70% confidence
Finding
Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Context-Inappropriate Capability

Low
Confidence
85% confidence
Finding
The module docstring and CLI description present this as a static HTML generator for browsing prompt data, but the code also searches for and parses `config.json` or `config_example.json` at startup. Reading extra local configuration is not obviously required by the stated purpose in this file's documentation, which frames the tool as operating on the provided vault input and output paths.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The generated document sets `lang="en"`, which enforces an English locale choice in the output. Under the policy, locale constraints should be user-selectable or clearly justified; this file does not offer any language/locale opt-in or explain why English is required.

Static analysis

No suspicious patterns detected.