Back to skill

Security audit

閱讀筆記精靈

Security checks for vulnerabilities and agentic risk

Overview

This reading-notes skill is mostly coherent, but it can send extracted document text to an unvalidated model endpoint configured through the environment.

Install only if you are comfortable with your book titles and extracted PDF/EPUB text being sent to the selected model provider. Use --provider offline for sensitive documents, and do not set LOCAL_MODEL_URL unless it points to a local endpoint you control, preferably localhost. Pin dependencies before production use.

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

Warning
Location
scripts/book_summarizer.py:147
Finding

Unrestricted Model Endpoint Can Receive Extracted Document Content over Plaintext HTTP

Content
View full analysis
str: url = os.environ.get("LOCAL_MODEL_URL", "http://localhost:11434/api/generate") model = os.environ.get("LOCAL_MODEL", "llama3") payload = { "model": model, "prompt": f"\n{system}\n\n\n\n{user}\n", "stream": False, "options": {"num_predict": max_tokens}, } try: import urllib.request, json as _json data = _json.dumps(payload).encode() req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"}) with urllib.request.urlopen(req, timeout=120) as r: resp = _json.loads(r.read()) return resp.get("response", "") ``` The extracted chapter content is incorporated directly into model requests: ```python for chunk_idx, chunk in enumerate(chunks): prompt = self.llm._chapter_prompt(i, title) user = prompt.format(content=chunk) raw = self.llm.call(self.llm._system_prompt(), user, max_tokens=2048) parsed = self._parse_json(raw) if parsed: chapter_notes.append(parsed) ``` ### Technical Analysis The Skill legitimately requires network transmission when a user explicitly chooses a cloud-based OpenAI or Anthropic model. However, the local-model implementation exceeds the minimum privileges expected from its declared local Ollama mode. If `LOCAL_MODEL_URL` exists in the process environment, the applicat ...[truncated 2825 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (38)

Tainted flow: 'req' from os.environ.get (line 158, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
91% confidence
Finding

The local-model request target is taken from the LOCAL_MODEL_URL environment variable and then used directly in urllib.request.urlopen. If an attacker can influence environment variables or deployment configuration, they can redirect book contents and prompts to an arbitrary remote server, causing silent data exfiltration or SSRF-like outbound connections.

Content

Scanner excerpt · scripts/book_summarizer.py (reported line 160)May include surrounding context.

python
data = _json.dumps(payload).encode()
            req = urllib.request.Request(url, data=data,
                headers={"Content-Type": "application/json"})
            with urllib.request.urlopen(req, timeout=120) as r:
                resp = _json.loads(r.read())
            return resp.get("response", "")
        except Exception as e:

Tainted flow: 'req' from os.environ.get (line 158, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/book_summarizer.py (reported line 376)May include surrounding context.

python
q = urllib.parse.quote(book_name) if True else book_name
        url = f"https://openlibrary.org/search.json?q={q}&fields=title,author_name,subject,first_sentence&limit=1"
        req = urllib.request.Request(url, headers={"User-Agent": "reading-notes-genie/1.0"})
        with urllib.request.urlopen(req, timeout=10) as r:
            data = _json.loads(r.read())

        docs = data.get("docs", [])

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Representing the skill as a full reading-notes generator while it may actually function mainly as low-level text extraction is a meaningful integrity and transparency failure. In the presence of document uploads and possible OCR/network processing, inaccurate claims increase user exposure because people may submit private materials without understanding the real data flow or limitations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Representing the skill as a full reading-notes generator while it may actually function mainly as low-level text extraction is a meaningful integrity and transparency failure. In the presence of document uploads and possible OCR/network processing, inaccurate claims increase user exposure because people may submit private materials without understanding the real data flow or limitations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Representing the skill as a full reading-notes generator while it may actually function mainly as low-level text extraction is a meaningful integrity and transparency failure. In the presence of document uploads and possible OCR/network processing, inaccurate claims increase user exposure because people may submit private materials without understanding the real data flow or limitations.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Representing the skill as a full reading-notes generator while it may actually function mainly as low-level text extraction is a meaningful integrity and transparency failure. In the presence of document uploads and possible OCR/network processing, inaccurate claims increase user exposure because people may submit private materials without understanding the real data flow or limitations.

Content

No source excerpt is available for this finding.

Unvalidated Output Injection

High
Category
Output Handling
Confidence
95% confidence
Finding

Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.

Content

Scanner excerpt · scripts/pdf_extractor.py (reported line 176)May include surrounding context.

python
"""pdftotext CLI 工具(最穩定的 fallback)"""
    import subprocess
    try:
        proc = subprocess.run(
            ["pdftotext", "-layout", str(result.path), "-"],
            capture_output=True, timeout=60
        )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README explicitly promotes network-based book lookup and use of external AI providers, but it does not warn users that book titles, extracted text, highlights, or uploaded document contents may be transmitted to third-party services. In a reading-notes tool, this creates a real privacy and data-governance risk because users may process copyrighted, confidential, or personal documents without understanding the disclosure boundary.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill advertises and references capabilities that imply environment access, local file read/write, shell execution, and network use, but it does not declare any tool scope or permission boundaries. This is dangerous because users and hosting platforms cannot accurately assess or constrain what the skill may access, increasing the risk of unintended data exposure or excessive privilege during document processing and API calls.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger list contains broad everyday phrases such as generic note-taking or summarization terms, which can cause the skill to activate in contexts the user did not intend. This is dangerous because accidental activation could lead to unnecessary document access, network calls, or transmission of user content to external AI services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill does not warn users that uploaded documents or book queries may be sent to external AI providers or network services. This is dangerous because users may unknowingly transmit sensitive, personal, or copyrighted material off-device, creating privacy, compliance, and confidentiality risks.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code sends book content, including uploaded local document text, to external LLM providers without any explicit notice, confirmation, or data-classification guard. In this skill context, users may upload copyrighted, private, or sensitive material, so silent transmission to third-party APIs creates a real confidentiality and compliance risk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest says users can input a book title and the AI will generate chapter summaries, quotes, takeaways, and knowledge cards. In this code path, the skill fetches only Open Library search metadata and subject tags, then asks the LLM for a full book-note structure without supplying actual book text, so the resulting behavior does not match the claimed content-based analysis.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The docstring at L368 states '搜尋網路取得書籍內容摘要', implying the function acquires summary content. However, the implementation builds a content string from Open Library subjects, then never inserts that content into the LLM call, instead sending a prompt template with an unformatted {content} placeholder, which contradicts the documented intent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

When processing local PDF/EPUB files, extracted content is sent to the configured LLM provider with no warning at the file-handling entry point. Because this skill is specifically designed to ingest user-supplied books/documents, the context makes the issue more serious: users may reasonably expect local analysis while the tool may upload entire documents to remote services.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The module title and description are written only in Chinese, and the rest of the script continues with Chinese-only user-facing strings and help text. For a general-purpose exporter, this imposes a language choice on users without opt-in or any documented region-specific justification, which matches the locale-policy violation criterion.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/notes_exporter.py (reported line 19)May include surrounding context.

python
# ── 依賴偵測 ─────────────────────────────────────────────────────────────────
def _has(mod: str) -> bool:
    try:
        __import__(mod); return True
    except ImportError:
        return False

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/pdf_extractor.py (reported line 18)May include surrounding context.

python
# ── 依賴偵測 ─────────────────────────────────────────────────────────────────
def _has(mod: str) -> bool:
    try:
        __import__(mod); return True
    except ImportError:
        return False

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill processes attacker-supplied PDFs by invoking external native tools, increasing the attack surface beyond pure Python parsing. If pdftoppm or pdftotext contains a memory-safety vulnerability, a crafted PDF could potentially trigger code execution or denial of service in the host environment.

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/pdf_extractor.py (reported line 155)May include surrounding context.

python
try:
        import subprocess
        # 用 pdftoppm(poppler-utils)轉圖片
        result = subprocess.run(
            ["pdftoppm", "-f", str(page_num), "-l", str(page_num),
             "-png", "-r", "200", str(pdf_path), "/tmp/ocr_page"],
            capture_output=True, timeout=30

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The OCR call forces lang="chi_sim+eng", which embeds a specific language/locale assumption in the skill behavior. The file does not expose a language option or clearly justify that the tool is intended only for Chinese/English PDFs, so this is a natural-language locale policy concern.

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/pdf_extractor.py (reported line 176)May include surrounding context.

python
"""pdftotext CLI 工具(最穩定的 fallback)"""
    import subprocess
    try:
        proc = subprocess.run(
            ["pdftotext", "-layout", str(result.path), "-"],
            capture_output=True, timeout=60
        )

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The entire skill description and usage guidance are presented in Traditional Chinese, branded as '閱讀筆記精靈', with no indication that users may choose another language or that the locale restriction is intentional. Under the policy, forcing a specific language without user opt-in can be a natural-language policy issue unless the regional constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency requests is completely unpinned, so builds may resolve to different versions over time, including versions with known vulnerabilities or breaking changes. In a skill that processes user-supplied documents and may make outbound API/network calls, supply-chain drift increases the risk of silently introducing exploitable behavior.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
# Core
requests
# PDF
pypdf>=4.0.0
pdfplumber>=0.10.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
96% confidence
Finding

requests has multiple known advisories, but because the manifest does not pin a version, there is no way to verify whether deployment uses a safe or affected release. In a skill likely to call external APIs, this uncertainty can translate into credential leakage, TLS/verification issues, or other client-side network weaknesses depending on the resolved version.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.