Back to skill

Security audit

Knowledge Base Collector

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly aligned with saving links and screenshots into a personal knowledge base, but it uses broad persistent storage and can expose full submitted URLs to a third-party extraction service without strong safeguards.

Install only if you are comfortable with saved links and extracted content being written persistently to the configured KB. Do not ingest private, signed, password-reset, invite, or token-bearing URLs unless they are redacted first, because full URLs are sent to r.jina.ai. Treat the macOS node WeChat path as an advanced manual action that should require explicit approval and a clearly reviewed command.

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/ingest_url.py:97
Finding

Full User-Supplied URLs Are Disclosed to a Third-Party Extraction Service

Content
View full analysis

Vulnerability Details

File Location: scripts/ingest_url.py, lines 97–103
Vulnerability Type: Sensitive information exposure through third-party URL proxying
Risk Level: Medium

Vulnerable Code

python
def fetch_r_jina(url: str, timeout: int = 40) -> str:
    # r.jina.ai returns a plain-text extracted representation.
    rurl = "https://r.jina.ai/" + url
    headers = {"User-Agent": "Mozilla/5.0"}
    r = requests.get(rurl, headers=headers, timeout=timeout)
    r.raise_for_status()
    return r.text

Technical Analysis

The function embeds the complete user-supplied URL in a request sent to the external r.jina.ai service. No validation or redaction is performed before transmission.

Consequently, the external service can receive sensitive URL components, including:

  • Query parameters containing access tokens or signed-resource credentials
  • Password-reset or account-verification links
  • Private document sharing URLs
  • Invitation codes and session identifiers
  • Credentials included in URL user-information fields
  • Private resource names and identifiers

Use of r.jina.ai is documented in SKILL.md, so the transmission is not covert. However, the implementation does not enforce the documentation's recommendation to redact sensitive data. It also lacks a consent gate, direct-fetch alternative, domain policy, and sensitive-parameter detection.

Sending public URLs to an extraction service supports the declared functionality. Sending arbitrary URLs in full exceeds the minimum data disclosure needed when the URL includes credentials or private identifiers.

Attack Path

  1. A user asks the Skill to ingest a private, signed, or tokenized URL.
  2. normalize_url() preserves the URL's query string and any embedded credentials.
  3. The URL reaches fetch_r_jina() without a sensitivity check.
  4. The function constructs https://r.jina.ai/ plus the complete original URL.
  5. The request exposes the complete URL to the third-party serv ...[truncated 860 chars]
Remediation
View remediation

Remediation Suggestions

  1. Reject URL credentials

    • Parse URLs with urllib.parse.urlsplit.
    • Reject URLs whose authority contains a username or password.
    • Permit only expected https URLs.
  2. Minimize query-string disclosure

    • Strip query strings and fragments by default.
    • Maintain a denylist for credential-like parameter names such as token, access_token, key, secret, signature, sig, auth, session, and code.
    • Prefer a narrowly scoped allowlist of parameters required for known public content providers.
  3. Require informed confirmation

    • Display the destination host and a redacted form of the URL before sending it to a third-party proxy.
    • Require explicit approval when query parameters are present or the domain is not on an approved public-domain list.
  4. Provide a privacy-preserving path

    • Offer direct retrieval as the default where technically possible.
    • Use the external extractor only as an explicit fallback.
    • Do not proxy private-network, localhost, or authenticated resource URLs.
  5. Improve handling and documentation

    • Clearly identify r.jina.ai as a third-party data processor.
    • Explain that submitted URLs may be visible in service and intermediary logs.
    • Redact sensitive parameters from console output, stored metadata, and error messages.
  6. Add automated tests

    • Verify that URLs containing user information are rejected.
    • Verify that sensitive query parameters are removed or require confirmation.
    • Verify that ordinary public URLs continue to work as intended.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill description promises broader capabilities than are reliably implemented, including WeChat/macOS-node retrieval and Telegram search flows. This mismatch can cause the agent or user to assume actions occurred safely or completely when the actual behavior is partial, placeholder-only, or absent, which is dangerous in a security-sensitive automation context because data handling and trust boundaries become unclear.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill description promises broader capabilities than are reliably implemented, including WeChat/macOS-node retrieval and Telegram search flows. This mismatch can cause the agent or user to assume actions occurred safely or completely when the actual behavior is partial, placeholder-only, or absent, which is dangerous in a security-sensitive automation context because data handling and trust boundaries become unclear.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill instructs the agent to perform network access and write files into a shared KB path, but it declares no explicit tool scope or allowed-tools boundaries. In practice this increases the blast radius of accidental or prompt-injected execution because the agent may invoke broader file, environment, or network capabilities than the user expects.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger phrases are broad enough to activate on common requests about saving links, screenshots, or searching knowledge, which can cause the skill to run in contexts the user did not explicitly intend. Because the skill performs network ingestion and persistent file writes, overbroad activation raises the risk of unintended data collection, storage of sensitive material, or exploitation through malicious URLs/content.

Content

No source excerpt is available for this finding.

Tainted flow: 'img_out' from os.environ.get (line 108, credential/environment) → shutil.copyfile (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/ingest_image.py (reported line 109)May include surrounding context.

python
# copy image
    ext = os.path.splitext(img_path)[1].lower() or ".img"
    img_out = os.path.join(entry_dir, f"image{ext}")
    shutil.copyfile(img_path, img_out)

    note = args.note.strip() or None

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The generated markdown content uses Chinese headings and placeholder text (e.g. '备注' and '未做 OCR...') regardless of user preference. This is a natural-language locale policy issue because the skill forces a specific language in user-facing output without opt-in or justification.

Content

No source excerpt is available for this finding.

Tainted flow: 'entry_dir' from os.environ.get (line 103, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/ingest_image.py (reported line 143)May include surrounding context.

python
if note:
        meta["note"] = note

    with open(os.path.join(entry_dir, "content.md"), "w", encoding="utf-8") as f:
        f.write(content)
    with open(os.path.join(entry_dir, "meta.json"), "w", encoding="utf-8") as f:
        json.dump(meta, f, ensure_ascii=False, indent=2)

Tainted flow: 'entry_dir' from os.environ.get (line 103, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/ingest_image.py (reported line 145)May include surrounding context.

python
with open(os.path.join(entry_dir, "content.md"), "w", encoding="utf-8") as f:
        f.write(content)
    with open(os.path.join(entry_dir, "meta.json"), "w", encoding="utf-8") as f:
        json.dump(meta, f, ensure_ascii=False, indent=2)

    idx_path = index_path(kb_root)

Tainted flow: 'idx_path' from os.environ.get (line 148, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/ingest_image.py (reported line 159)May include surrounding context.

python
"status": status,
        "source": source,
    }
    with open(idx_path, "a", encoding="utf-8") as f:
        f.write(json.dumps(rec, ensure_ascii=False) + "\n")

    print(entry_dir)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The file switches from English to Chinese for core operational instructions and headings without stating that the user can choose their preferred language. This can violate a language-choice policy when a skill imposes a locale or language implicitly rather than offering an opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The function assigns #lang:zh whenever Chinese characters are present and #lang:en whenever Latin letters are present, embedding a fixed locale classification policy into the skill. This is a natural-language policy concern because the file imposes language categorization for only two languages without any user opt-in or explanation of why this limitation is appropriate.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.