Back to skill

Security audit

Summarize All

Security checks for vulnerabilities and agentic risk

Overview

This is a real summarization tool, but its optional API server can expose local files and network requests without authentication.

Review before installing. Use this only with trusted inputs and trusted model endpoints. Do not run `summarize-all server` on a networked machine unless it is bound to localhost, protected by authentication, and restricted from reading arbitrary local paths or reaching internal network destinations. Treat the stored API key, cache, history, tags, and keyword files as sensitive local data.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/summarize-all.py:824
Finding

Unauthenticated Network API Permits Arbitrary Local File Processing and Disclosure

Content
View full analysis

Vulnerability Details

File Location: scripts/summarize-all.py:637-651, scripts/summarize-all.py:824-839, and scripts/summarize-all.py:882
Vulnerability Type: Unauthenticated local file access through a network-facing API
Risk Level: High

Vulnerable Code

python
def get_content(input_url):
    if 'youtube.com' in input_url or 'youtu.be' in input_url:
        return fetch_youtube(input_url)
    elif input_url.startswith(('http://', 'https://')):
        return fetch_url(input_url)
    elif os.path.isfile(input_url):
        ext = pathlib.Path(input_url).suffix.lower()
        fetchers = {'.pdf': fetch_pdf, '.jpg': fetch_image, '.jpeg': fetch_image, '.png': fetch_image,
                    '.gif': fetch_image, '.webp': fetch_image, '.mp3': fetch_audio, '.wav': fetch_audio,
                    '.mp4': fetch_audio, '.m4a': fetch_audio, '.ogg': fetch_audio}
        if ext in fetchers:
            return fetchers[ext](input_url)
        try:
            return open(input_url).read()[:15000]
        except:
            return "[Read error]"
    return input_url
python
class Handler(http.server.BaseHTTPRequestHandler):
    def log_message(self, fmt, *args):
        pass
    
    def do_POST(self):
        if self.path != '/summarize':
            self.send_error(404)
            return
        try:
            length = int(self.headers.get('Content-Length', 0))
            data = json.loads(self.rfile.read(length).decode())
            
            url = data.get('url', '')
            lang = data.get('lang', 'auto')
            
            summary, ctype, tags = summarize(url, 'auto', lang, True, True)
python
with socketserver.TCPServer(("", port), Handler) as httpd:
    httpd.serve_forever()

Technical Analysis

The HTTP server binds to all available network interfaces by passing an empty host string to TCPServer. The `/s ...[truncated 2566 chars]

Remediation
View remediation

Remediation Suggestions

  1. Bind the server to 127.0.0.1 by default rather than all interfaces:

    python
    with socketserver.TCPServer(("127.0.0.1", port), Handler) as httpd:
        httpd.serve_forever()
    
  2. Require a cryptographically strong API token for every non-health endpoint. Compare tokens using hmac.compare_digest.

  3. Disable local-path inputs in server mode unless explicitly enabled by an administrator.

  4. If remote local-file processing is required, configure a dedicated document root and enforce it with canonical path checks:

    python
    root = pathlib.Path(configured_root).resolve()
    candidate = pathlib.Path(user_path).resolve()
    if candidate != root and root not in candidate.parents:
        raise PermissionError("Path is outside the permitted document root")
    
  5. Run the server under a dedicated, unprivileged operating-system account with access only to intended input files.

  6. Add request-body size limits, rate limiting, audit logging, and explicit timeouts.

  7. Do not send local content to an external model provider without clear per-request authorization and disclosure.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/summarize-all.py:563
Finding

Unauthenticated Source and Webhook Parameters Enable Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: scripts/summarize-all.py:563-569 and scripts/summarize-all.py:824-853
Vulnerability Type: Server-side request forgery through arbitrary source URLs and webhook destinations
Risk Level: High

Vulnerable Code

python
def fetch_url(url):
    try:
        req = urllib.request.Request(url, headers={
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0',
            'Accept': 'text/html,application/xhtml+xml'
        })
        with urllib.request.urlopen(req, timeout=30) as resp:
            html = resp.read().decode('utf-8', errors='ignore')
python
def do_POST(self):
    if self.path != '/summarize':
        self.send_error(404)
        return
    try:
        length = int(self.headers.get('Content-Length', 0))
        data = json.loads(self.rfile.read(length).decode())
        
        url = data.get('url', '')
        lang = data.get('lang', 'auto')
        
        summary, ctype, tags = summarize(url, 'auto', lang, True, True)
        
        result = {"summary": summary, "type": ctype, "tags": tags}
        
        # Webhook
        if data.get('webhook'):
            try:
                req = urllib.request.Request(
                    data['webhook'],
                    data=json.dumps(result).encode(),
                    headers={'Content-Type': 'application/json'},
                    method='POST'
                )
                urllib.request.urlopen(req, timeout=10)
            except:
                pass

Technical Analysis

The unauthenticated /summarize endpoint accepts two attacker-controlled network destinations:

  • url, which is fetched by fetch_url() for HTTP and HTTPS inputs.
  • webhook, which receives an outbound POST request containing the result.

Neither destination is validated against an allowlist. The code does not rejec ...[truncated 2572 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require authentication and authorization before accepting source URLs or webhook destinations.
  2. Permit only explicitly required schemes, preferably HTTPS. Reject file, ftp, and other unnecessary schemes.
  3. Resolve destination hostnames before connecting and reject every address in loopback, private, link-local, multicast, unspecified, and reserved ranges.
  4. Revalidate the destination after every redirect. Prefer disabling redirects unless explicitly required.
  5. Use a strict hostname allowlist for webhook destinations and, where practical, for source retrieval.
  6. Protect against DNS rebinding by connecting to the validated resolved address while preserving the expected TLS hostname and Host value.
  7. Apply outbound firewall or proxy controls so the process cannot reach metadata services, localhost, or internal administrative networks.
  8. Disable webhooks by default and require an administrator-configured allowlist before enabling them.
  9. Limit response sizes, request duration, redirect count, and concurrent outbound requests.
  10. Return generic errors and record rejected SSRF attempts in security logs without exposing sensitive internal response details.
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The manifest describes a summarization tool, but the documented behavior includes running an HTTP server, sending webhooks to arbitrary URLs, maintaining history/tags/keywords, batch processing, and other actions beyond basic summarization. This mismatch is dangerous because users and policy systems may grant trust based on the benign description while the skill exposes additional data-handling and network-facing functionality.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/summarize-all.py (reported line 475)May include surrounding context.

python
if len(contents) < 2:
        print_step("error", "Need at least 2 valid articles")
        return
    
    prompt = f"""## Task: Multi-Article Comparison

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill advertises capabilities that imply network access, shell execution, and local file writes, but it declares no explicit tool scope or permission boundaries. In an agent environment, this creates an authorization gap where operators may assume the skill is limited to summarization while it can also fetch remote content, run local commands, and persist data.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Advertising a --think option that reveals chain-of-thought can expose internal reasoning, prompt structure, or sensitive intermediate data derived from user content. In a summarization tool that processes webpages, PDFs, audio, and other potentially sensitive inputs, this increases the chance of leaking secrets, private text, or system-prompt artifacts to users or logs.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 214)May include surrounding context.

Config

bash
summarize-all config set endpoint "https://api.minimax.chat/v1"
summarize-all config set key "your-key"
summarize-all config set model "MiniMax-Text-01"
summarize-all config show

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest description is written entirely in Chinese and presents the skill as a Chinese-language tool, with no indication that users can choose another language or that the skill is intentionally limited to a Chinese-speaking context. This creates a natural-language locale policy concern because it implies a fixed language experience without user opt-in or documented justification.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This script invokes external binaries such as notify-send, pdftotext, pdftk, and a summarize CLI via subprocess. While some content extraction may support summarization, spawning arbitrary local executables and desktop notifications is a broader host capability than the manifest's high-level description suggests.

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/summarize-all.py (reported line 180)May include surrounding context.

python
def send_notification(title, message):
    """Send desktop notification"""
    try:
        subprocess.Popen(['notify-send', title, message])
    except:
        pass

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Fetched content is sent to a remote LLM endpoint configured in the skill without an explicit user-facing warning or consent flow. In a summarization tool this can expose sensitive local file contents, private URLs, or proprietary documents to third-party services, making the privacy risk material in context.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest emphasizes automatic summarization, caching, and key point extraction across content types. The code adds substantial adjacent features such as persistent history search, tag extraction/storage, keyword alerting with notifications, multi-article comparison, and specialized academic analysis, which materially broaden the skill's stated behavior.

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/summarize-all.py (reported line 364)May include surrounding context.

python
def merge_pdfs(pdf_paths, output_path):
    """Merge multiple PDFs into one"""
    try:
        result = subprocess.run(
            ['pdftk'] + pdf_paths + ['cat', 'output', output_path],
            capture_output=True, timeout=60
        )

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/summarize-all.py (reported line 582)May include surrounding context.

python
def fetch_pdf(path):
    try:
        result = subprocess.run(['pdftotext', '-layout', path, '-'], capture_output=True, text=True, timeout=30)
        return result.stdout[:15000] if result.stdout else "[No text]"
    except:
        return "[pdftotext not found]"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Local image contents are base64-encoded and uploaded to an external vision API with no explicit warning. Because users may summarize screenshots, IDs, medical images, or other sensitive media, silent exfiltration to a third party creates a meaningful privacy and compliance risk.

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/summarize-all.py (reported line 617)May include surrounding context.

python
def fetch_youtube(url):
    try:
        result = subprocess.run(['summarize', url, '--extract-only'], capture_output=True, text=True, timeout=30)
        return result.stdout[:15000] if result.stdout else "[No transcript]"
    except:
        return "[summarize CLI not found]"

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/summarize-all.py (reported line 624)May include surrounding context.

python
def fetch_audio(path):
    try:
        result = subprocess.run(['summarize', path, '--extract-only'], capture_output=True, text=True, timeout=60)
        return result.stdout[:15000] if result.stdout else "[Transcription failed]"
    except:
        return "[summarize CLI not found]"

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill exposes a local HTTP API server with no authentication or authorization checks, significantly broadening attack surface beyond summarization. If bound on a reachable interface, other local users or network peers may trigger summarization, SSRF-like fetches, history/tag side effects, and webhook posts without user consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The server can forward generated summaries and metadata to any caller-supplied webhook URL, which can leak processed content to arbitrary third parties. Combined with the unauthenticated server, this creates a practical exfiltration path for summaries and tags.

Content

No source excerpt is available for this finding.

Tainted flow: 'req' from urllib.request.urlopen (line 846, network input) → urllib.request.urlopen (network output)

Medium
Category
Data Flow
Confidence
96% confidence
Finding

The local HTTP server accepts a user-supplied webhook URL and performs a server-side POST to it with urllib, creating an SSRF primitive. An attacker who can access the server can coerce the host into making outbound requests to internal services, localhost-only endpoints, or cloud metadata addresses, which is more dangerous because the skill exposes this feature over HTTP.

Content

Scanner excerpt · scripts/summarize-all.py (reported line 852)May include surrounding context.

python
headers={'Content-Type': 'application/json'},
                            method='POST'
                        )
                        urllib.request.urlopen(req, timeout=10)
                    except:
                        pass

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest description is written entirely in Chinese, which can create a language-specific user experience without indicating that other languages are available or optional. The policy for natural-language violations requires flagging language or locale constraints when no user choice or opt-in is provided.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The section is labeled 'PDF Merge & Summarize' and announces 'Merging' PDFs, but summarize_pdfs only extracts text from each input PDF individually and never calls merge_pdfs or writes the merged_path. This is an active mismatch between the documented/announced behavior and the actual implementation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The prompt builder instructs the model to summarize in a language selected from automatic language detection, and the default summarize flow uses detected language when the user does not specify one. This creates a language-selection policy issue because the output language is imposed automatically rather than offered as an explicit user choice.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.