Back to skill

Security audit

Clipper

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent Obsidian web clipper, but it automatically commits and pushes saved content and depends on third-party fetching tools, so users should review it before installing.

Review this before installing. It will fetch URLs through external services/tools, write files into your Obsidian vault, and automatically run git pull, commit, and push from that vault. Use it only with a vault and git remote where publishing clipped content is acceptable, and prefer pinning or reviewing the x-reader dependency before installation.

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

T08 · Insecure Dependencies

Warning
Location
SKILL.md:78
Finding

Unpinned dependency installed from a mutable Git repository

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:78-82; also referenced in scripts/web.py:63-65
Vulnerability Type: Supply-chain exposure through an unpinned source dependency
Risk Level: Medium

Vulnerable Code

SKILL.md:78-82:

markdown
## Requirements

- `obsidian-cli` (for vault detection) OR manually configured vault path
- `x-reader` for general web: `pipx install 'git+https://github.com/runesleo/x-reader.git'`

scripts/web.py:63-65:

python
except FileNotFoundError:
    return {"success": False, "error": "x-reader not installed. Run: pipx install 'git+https://github.com/runesleo/x-reader.git'"}

Technical Analysis

The documented installation command installs x-reader directly from the mutable default branch of a Git repository. It does not specify an audited release tag, immutable commit hash, package hash, or signature.

Consequently, the code installed by users can differ from the code that existed when this Skill was audited. A compromise of the upstream repository, maintainer account, or default branch could introduce malicious package build hooks or replace the installed x-reader executable. Python package installation can execute build-related code, and the Skill later invokes the resulting executable through:

python
subprocess.run(
    ["x-reader", url],
    capture_output=True, text=True, timeout=60
)

The use of an argument array prevents shell metacharacter injection through url, but it does not protect against a malicious or compromised x-reader executable.

Attack Path

  1. An attacker compromises the upstream x-reader repository, a maintainer account, or another mechanism controlling its default branch.
  2. The attacker adds malicious installation hooks or modifies the x-reader executable.
  3. A user follows the installation instruction exposed by the Skill:
    bash
    pipx install 'git+https://github.com/runesleo/x
    

...[truncated 905 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin the dependency to an immutable, reviewed commit rather than the repository's mutable default branch:
    bash
    pipx install 'git+https://github.com/runesleo/x-reader.git@<audited-full-commit-hash>'
    
  2. Prefer a trusted package registry release with an exact version and verified package hashes.
  3. Record the expected source revision and integrity information in the Skill documentation or a lockfile.
  4. Review package build configuration and installation hooks before approving dependency updates.
  5. Apply dependency updates through an explicit review process rather than automatically tracking upstream branch changes.
  6. Run the dependency with least privilege and restrict access to credentials and unrelated user files where sandboxing is available.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/web.py:86
Finding

Untrusted metadata can inject or corrupt YAML frontmatter

Content
View full analysis

Vulnerability Details

File Location: scripts/web.py:86-103; the same issue occurs in scripts/wechat.py:42-57
Vulnerability Type: Improper neutralization of untrusted data in generated YAML and Markdown
Risk Level: Low

Vulnerable Code

scripts/web.py:86-103:

python
safe_title = (title[:100] if title else 'Untitled').replace('"', "'")
display_title = title if title else 'Untitled'

frontmatter = f'''---
source: web
url: {url}
domain: {domain}
platform: {platform}
method: {method}
clipped: {datetime.now().isoformat()}
title: "{safe_title}"
---

# {display_title}

'''

scripts/wechat.py:42-57:

python
# Escape title quotes
safe_title = (title[:100] if title else 'Untitled').replace('"', "'")

# Build frontmatter
frontmatter = f'''---
source: web
url: {url}
domain: mp.weixin.qq.com
platform: wechat
method: browser-snapshot
clipped: {datetime.now().isoformat()}
title: "{safe_title}"
author: "{author or ''}"
publish_date: "{date or ''}"
---

# {title or 'Untitled'}

'''

Technical Analysis

Remote or externally supplied metadata is inserted directly into a YAML frontmatter template. Replacing double quotes in the title does not remove line breaks, carriage returns, YAML document delimiters, or other control syntax. The URL, author, and publication date receive no YAML-specific escaping at all.

In the general web flow, the title is extracted from the output of x-reader, which processes attacker-controlled web content. In the WeChat flow, title, author, date, and URL values are supplied through command-line arguments after browser extraction and can originate from an attacker-controlled article.

A malicious value containing a newline can escape its intended scalar position and add properties or prematurely terminate the frontmatter. For example, an attacker-controlled title conceptually containing:

text
Article"
attacker_prope
...[truncated 1484 chars]
Remediation
View remediation

Remediation Suggestions

  1. Construct frontmatter as a dictionary and serialize it with a maintained safe YAML serializer instead of interpolating strings.
  2. Normalize or reject carriage returns, line feeds, NUL bytes, and other control characters in all metadata fields.
  3. Validate URLs with urllib.parse.urlparse and permit only expected http and https schemes.
  4. Apply explicit length limits to title, author, date, URL, domain, platform, and method fields.
  5. If a YAML dependency is undesirable, encode every scalar using a robust JSON string encoder because JSON-quoted strings are valid YAML scalars:
    python
    encoded_title = json.dumps(title or "Untitled", ensure_ascii=False)
    
  6. Escape or normalize heading text separately from YAML metadata because Markdown headings have different encoding requirements.
  7. Add regression tests using metadata containing newlines, ---, quotes, colons, backslashes, Unicode control characters, and YAML-looking keys.
Vulnerability Patterns
  • 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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The skill advertises automatic platform-aware clipping, but the documented behavior shows gaps: some claimed platforms lack explicit handling and WeChat requires a separate manual browser workflow. Security-relevant mismatches like this can cause agents or users to trust unsupported paths, leading to unsafe fallback behavior, incorrect automation assumptions, or unexpected handling of untrusted web content.

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

python
if platform == "twitter":
        return twitter.clip_twitter(url, vault_path)
    elif platform == "wechat":
        # WeChat needs browser - return instruction for agent
        return {
            "success": False,
            "needs_browser": True,

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes Python scripts, performs network retrieval, writes into an Obsidian vault, and documents browser and git-related side effects, but it does not declare any explicit tool scope or permissions. This increases the chance that an agent executes broader capabilities than a user expects, reducing transparency and weakening policy enforcement around shell, network, and file-write actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill states that every save triggers automatic git operations including pull, commit, and push, but gives no user warning or consent checkpoint. This can exfiltrate clipped content to a remote repository, overwrite local state through rebase, or create unintended persistent changes, which is especially risky for content pulled from arbitrary URLs and saved into a personal knowledge base.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Importing and using git_sync adds repository interaction capabilities that are not an obvious requirement of clipping web content into an Obsidian vault. Based on the manifest, the expected scope is fetching content and saving it locally; repository synchronization is a separate capability that should be explicitly justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script sends the target Twitter/X URL to the external Jina Reader service for fetching and transformation, which shares user-requested content with a third party. In a clipping tool, this is a meaningful privacy and trust issue because users may expect local retrieval, and the file provides no visible disclosure or consent flow for that data transfer.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This function creates directories and writes a markdown file into the vault path, modifying user data on disk. The code does not provide a confirmation prompt or visible user-facing disclosure about the file write operation in this file; internal docstrings alone are not sufficient as a warning to users.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill performs a git synchronization step after saving content, which expands its capabilities from local clipping into repository-modifying behavior. That can cause unintended commits, pushes, or disclosure of newly clipped content if the vault is backed by a remote repository, and this extra action is not necessary to fulfill the stated clipping function.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Automatic git synchronization can perform repository-changing actions after clipping, potentially committing and propagating data without explicit user awareness at the time of use. In the context of a web clipper, that broadens the trust boundary and can turn a local save into a wider disclosure event if the repository is synced remotely.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The skill invokes external executables (obsidian-cli here and git elsewhere), which introduces trust in the host environment and expands capability beyond simple in-process clipping logic. In an agent skill, undeclared subprocess execution is riskier because it can interact with local tools, files, and networked workflows in ways users may not anticipate.

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

python
# Try obsidian-cli default
    try:
        result = subprocess.run(
            ["obsidian-cli", "print-default", "--path-only"],
            capture_output=True, text=True, timeout=10
        )

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The helper includes git synchronization behavior that exceeds the stated purpose of saving clipped web content to an Obsidian vault. This hidden scope expansion is dangerous because users may expect a local write-only tool, while the code can modify a repository state and transmit data to configured remotes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

git_sync performs pull, commit, and push with no user-facing warning or confirmation, enabling silent repository modification and remote publication of content. In the context of a web-clipping skill, this is especially dangerous because clipped pages may contain sensitive notes or private source material that users did not intend to sync externally.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
89% confidence
Finding

This code executes repository-modifying and network-capable git commands (pull, add, commit, push) against a dynamically chosen vault_path without any confirmation or visible policy checks. In the context of a clipping skill, this expands behavior from local content saving to automatic synchronization, which can exfiltrate clipped data to a remote repository or alter an unintended repository if the path is influenced upstream.

Content

Scanner excerpt · scripts/utils.py (reported line 73)May include surrounding context.

python
errors = []
    for cmd in commands:
        try:
            result = subprocess.run(
                cmd, cwd=vault_path,
                capture_output=True, text=True, timeout=30
            )

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The skill invokes an external CLI, x-reader, to fetch and process remote content, but this capability is not disclosed by the stated clipping purpose. Running an undeclared third-party executable increases supply-chain and data-handling risk because users may not realize external code is being executed on untrusted URLs.

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

python
def fetch_with_x_reader(url):
    """Fetch content using x-reader CLI."""
    try:
        result = subprocess.run(
            ["x-reader", url],
            capture_output=True, text=True, timeout=60
        )

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The workflow automatically retrieves remote content, writes it into the user's Obsidian vault, and may then sync it via git without an explicit warning or confirmation. In a clipping skill this behavior is partly expected, but the lack of transparent notice still makes accidental persistence and onward disclosure more dangerous, especially for sensitive or private URLs.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

After saving content locally, the skill automatically performs git synchronization, which can transmit clipped data and repository metadata beyond the local vault. That exceeds the stated save-to-vault behavior and creates a privacy and integrity risk if users do not expect content to be committed or pushed to a remote repository.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The skill includes a Chinese-only example input (保存这个) and targets Chinese platforms such as WeChat and Xiaohongshu, but it does not state whether the skill supports multiple languages or is intentionally region/language-specific. This can be read as a locale preference baked into the skill without explicit opt-in or justification.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest enumerates supported sources such as Twitter/X, WeChat MP, Xiaohongshu, YouTube, Bilibili, and generic web pages. The code additionally recognizes Telegram URLs as a first-class platform, which creates a mismatch between the advertised supported platforms and implemented behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.