Back to skill

Security audit

Screenshot Tool

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do screenshots and document conversion, but crafted URLs or file paths could make it run unintended local commands.

Install only if you trust the publisher and can run it in a constrained environment. Avoid passing untrusted URLs, filenames, or output paths until the scripts stop using shell=True and validate inputs; also review the global npm, pip, and sudo installation steps before running them on a primary machine.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/web_screenshot.py:13
Finding

OS Command Injection Through Web Screenshot Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/web_screenshot.py, lines 13–21, 36–37, and 50–51
Vulnerability Type: OS command injection through shell command construction
Risk Level: High

Vulnerable Code:

python
def run_command(cmd, timeout=120):
    """Run a command and return its result."""
    try:
        result = subprocess.run(
            cmd,
            shell=True,
            capture_output=True,
            text=True,
            timeout=timeout
        )
python
cmd = f'agent-browser open "{url}" --timeout {timeout}'
success, stdout, stderr = run_command(cmd, timeout=timeout//1000 + 10)
python
full_arg = "--full" if full_page else ""
cmd = f'agent-browser screenshot "{output}" {full_arg}'
success, stdout, stderr = run_command(cmd, timeout=60)

Technical Analysis

The --url and --output command-line arguments are inserted directly into shell command strings. The resulting strings are executed with subprocess.run(..., shell=True).

Placing an argument inside double quotes does not make shell execution safe. An attacker can supply a value containing a closing double quote followed by shell metacharacters and an additional command. The shell parses this syntax before invoking agent-browser, allowing the additional command to execute independently.

Both the URL passed to agent-browser open and the output path passed to agent-browser screenshot are affected. Numeric arguments are parsed by argparse as integers and are not the primary injection vector.

Attack Path

  1. An attacker gains control over the --url or --output value supplied to the script.
  2. The attacker includes a closing quote and shell control syntax in that value.
  3. screenshot_webpage() interpolates the malicious value into the cmd string.
  4. run_command() invokes the generated string with shell=True.
  5. The operating-system shell interprets th ...[truncated 644 chars]
Remediation
View remediation

Remediation Suggestions

Remove shell interpretation and pass each command argument as a separate list element:

python
def run_command(cmd, timeout=120):
    try:
        result = subprocess.run(
            cmd,
            shell=False,
            capture_output=True,
            text=True,
            timeout=timeout,
            check=False,
        )
        return result.returncode == 0, result.stdout, result.stderr
    except subprocess.TimeoutExpired:
        return False, "", "Command timed out"
python
open_cmd = [
    "agent-browser",
    "open",
    url,
    "--timeout",
    str(timeout),
]
python
screenshot_cmd = ["agent-browser", "screenshot", output]
if full_page:
    screenshot_cmd.append("--full")

Additionally:

  • Restrict URLs to explicitly supported schemes, preferably http and https.
  • If requests originate from untrusted users, apply destination controls to prevent access to loopback, link-local, private, or otherwise sensitive network resources.
  • Resolve output paths and restrict them to an approved output directory.
  • Reject negative or unreasonably large timeout and wait values.
  • Close the browser in a finally block so failure paths do not leave browser processes running.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/doc_screenshot.py:16
Finding

OS Command Injection Through Document Conversion Paths

Content
View full analysis

Vulnerability Details

File Location: scripts/doc_screenshot.py, lines 16–21 and 42–43
Vulnerability Type: OS command injection through shell command construction
Risk Level: High

Vulnerable Code:

python
def run_command(cmd, timeout=120):
    """Run a command and return its result."""
    try:
        result = subprocess.run(
            cmd,
            shell=True,
            capture_output=True,
            text=True,
            timeout=timeout
        )
python
cmd = f'libreoffice --headless --convert-to pdf --outdir "{output_dir}" "{input_file}"'
success, stdout, stderr = run_command(cmd, timeout=120)

Technical Analysis

The input filename and output directory are incorporated directly into a shell command. Although the values are surrounded by double quotes, filenames and directory names can themselves contain double quotes and shell metacharacters on supported operating systems.

The input existence check does not prevent exploitation. An attacker who can create or select a file with a maliciously constructed name can satisfy the check before the filename is interpolated into the command. The output directory is also created before conversion and can contain shell-significant characters.

Because run_command() enables shell=True, the shell interprets injected operators rather than treating each supplied path as a literal LibreOffice argument.

Attack Path

  1. An attacker creates or selects an existing input file with a shell-significant filename, or controls a crafted output-directory path.
  2. The path passes the file existence check or is created by os.makedirs().
  3. convert_to_pdf() inserts the path into the LibreOffice command string.
  4. run_command() passes the command to an operating-system shell.
  5. The shell terminates the intended quoted argument and executes the attacker's additional command.
  6. The injected command runs with the ...[truncated 578 chars]
Remediation
View remediation

Remediation Suggestions

Invoke LibreOffice without a shell and supply arguments as a list:

python
cmd = [
    "libreoffice",
    "--headless",
    "--convert-to",
    "pdf",
    "--outdir",
    str(output_dir),
    str(input_file),
]
success, stdout, stderr = run_command(cmd, timeout=120)

Update run_command() to use shell=False, as follows:

python
result = subprocess.run(
    cmd,
    shell=False,
    capture_output=True,
    text=True,
    timeout=timeout,
)

Additional hardening should include:

  • Resolve the input and output paths with Path.resolve().
  • Restrict output to an approved directory when processing untrusted requests.
  • Reject unsupported input extensions before invoking LibreOffice.
  • Run LibreOffice and PDF parsers in a sandbox with minimal filesystem and network access because document parsers process complex, potentially hostile formats.
  • Apply file-size, page-count, DPI, memory, and execution-time limits to reduce denial-of-service exposure.
  • Run the converter as a dedicated, unprivileged account.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:34
Finding

Unpinned Third-Party Package Installation Instructions

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 34–38 and 43–55
Vulnerability Type: Unpinned third-party dependencies and non-reproducible installation
Risk Level: Medium

Vulnerable Commands:

bash
npm install -g agent-browser
bash
pip3 install pdf2image pillow

The installation steps repeat the same unpinned commands:

bash
npm install -g agent-browser
agent-browser install
agent-browser install --with-deps
bash
pip3 install pdf2image pillow

Technical Analysis

The documentation instructs users to install npm and Python packages without fixed versions or integrity verification. Consequently, each installation resolves whatever package versions the configured registries currently consider latest.

This makes installations non-reproducible and allows package behavior to change after the Skill has been reviewed. npm package installation may also execute lifecycle scripts. Installing the browser package globally expands the affected scope beyond an isolated project environment.

The audited project does not itself prove that any named dependency is malicious. The finding concerns unsafe dependency acquisition practices and the resulting exposure to registry compromise, maintainer-account compromise, dependency compromise, or an unsafe future release.

Attack Path

  1. A dependency publisher account, package registry, transitive dependency, or future release becomes compromised or introduces malicious behavior.
  2. A user follows the documented unpinned installation command.
  3. The package manager resolves and downloads the affected current version rather than a previously reviewed version.
  4. Package installation hooks or subsequently invoked package code execute on the user's system.
  5. For the global npm installation, the installed executable becomes available system-wide for that user or environment.

Impact Assessment

A successful s ...[truncated 498 chars]

Remediation
View remediation

Remediation Suggestions

  • Pin every direct dependency to a reviewed exact version.
  • Maintain lockfiles for npm and Python dependencies.
  • For Python deployments, use a requirements file containing hashes and install with pip install --require-hashes -r requirements.txt.
  • Use npm lockfiles and reproducible installation commands such as npm ci where applicable.
  • Verify package provenance, registry configuration, and published checksums or signatures before installation.
  • Review transitive dependencies and automate vulnerability scanning.
  • Install Python packages in a virtual environment and avoid global npm installation where possible.
  • Document the exact reviewed versions of agent-browser, pdf2image, and Pillow.
  • Run package installation as an unprivileged user and separate dependency installation from privileged operating-system package installation.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (19)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

该代码块的主要行为与声明中的“文档截图/文档转高清图片”部分基本一致,确实支持 PDF 以及通过 LibreOffice 处理 Word/Excel/PPT 类文档,并提供 300 DPI 默认输出与分页控制。但声明同时强调“网页截图 + 全页截图”这一能力,而代码中没有任何与网页截图相关的实现,例如浏览器自动化、URL 输入、页面渲染或整页截图逻辑。因此描述比实际代码更宽,存在能力描述不准确的情况。未发现额外的可疑未声明高风险能力;不匹配点主要是缺失网页截图能力。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

代码的核心功能与声明部分重合于“网页截图”,且支持整页截图,这一点基本一致。但声明强调还支持多种办公文档和 PDF 转高清图片,并保留原始样式、300 DPI 输出;在提供的代码中完全看不到文档转换逻辑、相关依赖调用、文件解析/渲染流程,也没有 DPI、分辨率或高清导出设置。因此,声明显著高于代码实际能力,属于描述与实际行为不符。

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The script has shell-execution capability via subprocess but the declared permissions reportedly do not cover that behavior. In an agent/skill environment, undocumented execution capability increases risk because reviewers and policy layers may not expect or constrain command execution appropriately.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
98% confidence
Finding

This is a true parameter-abuse issue because attacker-controlled parameters flow into a shell command execution sink. In the context of a document conversion skill, inputs are likely to be externally supplied, which makes command injection especially dangerous and can turn a simple conversion tool into arbitrary code execution on the host.

Content

Scanner excerpt · scripts/doc_screenshot.py (reported line 16)May include surrounding context.

python
def run_command(cmd, timeout=120):
    """运行命令并返回结果"""
    try:
        result = subprocess.run(
            cmd,
            shell=True,
            capture_output=True,

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

The tool wrapper passes shell=True to subprocess.run, enabling tool-parameter abuse when user-supplied values are embedded into shell command strings. In this skill, both the webpage URL and screenshot output path flow into those strings, so an attacker can potentially trigger arbitrary command execution on the host running the skill.

Content

Scanner excerpt · scripts/web_screenshot.py (reported line 16)May include surrounding context.

python
def run_command(cmd, timeout=120):
    """运行命令并返回结果"""
    try:
        result = subprocess.run(
            cmd,
            shell=True,
            capture_output=True,

Unrestricted Tool Access

Medium
Category
Excessive Agency
Confidence
91% confidence
Finding

The allowed-tools entry grants Bash access with a wildcard scope for the skill, which is broader than necessary for a screenshot/conversion workflow. If the skill scripts are invoked with user-controlled arguments or later modified, this broad shell capability can be abused to run unintended commands, access files beyond the task scope, or chain additional system actions.

Content

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

md
- 需要将 PPT/Word/PDF 转为图片
  - 需要高清文档截图
metadata: {"clawdbot":{"emoji":"📸","requires":{"bins":["libreoffice","pdftoppm","agent-browser"]}}}
allowed-tools: Bash(screenshot-tool:*)
dependencies:
  - agent-browser: "网页截图功能必需,用于 headless 浏览器截图"
  - libreoffice: "文档转换功能必需,用于 PPT/Word/Excel 转 PDF"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill advertises webpage screenshots but does not warn that opening a URL in a headless browser transmits the destination URL and page contents to an external browser tool/runtime. In security-sensitive environments, users may supply internal URLs, authenticated pages, or sensitive web content without realizing it will be processed outside the core agent context and persisted as screenshots.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The document-conversion workflow sends user-provided files through LibreOffice/pdf2image/poppler and writes derived images to disk, but the skill does not warn users about that data handling. Sensitive documents may contain confidential text, embedded metadata, or regulated information, and converting them via multiple tools increases the attack surface and persistence footprint.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
| 依赖 | 用途 | 安装命令 |
|------|------|---------|
| **agent-browser** | 网页截图 | `npm install -g agent-browser && agent-browser install` |
| **LibreOffice** | 文档转 PDF | `sudo apt-get install -y libreoffice-impress libreoffice-writer libreoffice-calc` |
| **poppler-utils** | PDF 处理 | `sudo apt-get install -y poppler-utils` |
| **Python 库** | PDF 转图片 | `pip3 install pdf2image pillow` |

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
| 依赖 | 用途 | 安装命令 |
|------|------|---------|
| **agent-browser** | 网页截图 | `npm install -g agent-browser && agent-browser install` |
| **LibreOffice** | 文档转 PDF | `sudo apt-get install -y libreoffice-impress libreoffice-writer libreoffice-calc` |
| **poppler-utils** | PDF 处理 | `sudo apt-get install -y poppler-utils` |
| **Python 库** | PDF 转图片 | `pip3 install pdf2image pillow` |

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
| 依赖 | 用途 | 安装命令 |
|------|------|---------|
| **agent-browser** | 网页截图 | `npm install -g agent-browser && agent-browser install` |
| **LibreOffice** | 文档转 PDF | `sudo apt-get install -y libreoffice-impress libreoffice-writer libreoffice-calc` |
| **poppler-utils** | PDF 处理 | `sudo apt-get install -y poppler-utils` |
| **Python 库** | PDF 转图片 | `pip3 install pdf2image pillow` |

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

md
| 依赖 | 用途 | 安装命令 |
|------|------|---------|
| **agent-browser** | 网页截图 | `npm install -g agent-browser && agent-browser install` |
| **LibreOffice** | 文档转 PDF | `sudo apt-get install -y libreoffice-impress libreoffice-writer libreoffice-calc` |
| **poppler-utils** | PDF 处理 | `sudo apt-get install -y poppler-utils` |
| **Python 库** | PDF 转图片 | `pip3 install pdf2image pillow` |

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

pip3 install pdf2image pillow

5. 安装中文字体(可选,用于中文文档)

sudo apt-get install -y fonts-wqy-zenhei fonts-wqy-microhei fonts-noto-cjk

text

### 验证安装

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

pip3 install pdf2image pillow

5. 安装中文字体(可选,用于中文文档)

sudo apt-get install -y fonts-wqy-zenhei fonts-wqy-microhei fonts-noto-cjk

text

### 验证安装

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

pip3 install pdf2image pillow

5. 安装中文字体(可选,用于中文文档)

sudo apt-get install -y fonts-wqy-zenhei fonts-wqy-microhei fonts-noto-cjk

text

### 验证安装

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The file-level description is written entirely in Chinese, and the command-line help strings throughout the script also assume Chinese as the required interaction language. There is no indication that the tool is intentionally region-specific or that users may choose another language, which can violate language/locale policy requirements.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The code invokes subprocess.run with shell=True on a command string that incorporates user-controlled input_file and output_dir values. Although the values are wrapped in double quotes, shell metacharacters such as embedded quotes or command substitution can still break out of quoting and lead to arbitrary command execution.

Content

Scanner excerpt · scripts/doc_screenshot.py (reported line 16)May include surrounding context.

python
def run_command(cmd, timeout=120):
    """运行命令并返回结果"""
    try:
        result = subprocess.run(
            cmd,
            shell=True,
            capture_output=True,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file’s natural-language description is written as a Chinese-only title and the CLI help/docstrings throughout the script are also Chinese, with no indication that users may choose another language. The policy explicitly flags language or locale constraints when they are imposed without user opt-in or documented justification.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The helper executes arbitrary shell strings with shell=True, and elsewhere those strings are built using user-controlled inputs such as url and output. This creates a command injection path where crafted shell metacharacters can break out of the intended agent-browser invocation and execute arbitrary OS commands.

Content

Scanner excerpt · scripts/web_screenshot.py (reported line 16)May include surrounding context.

python
def run_command(cmd, timeout=120):
    """运行命令并返回结果"""
    try:
        result = subprocess.run(
            cmd,
            shell=True,
            capture_output=True,

Static analysis

No suspicious patterns detected.