Back to skill

Security audit

PDF Report

Security checks for vulnerabilities and agentic risk

Overview

This PDF skill largely matches its stated purpose, but its custom template feature gives templates more power than users are clearly warned about.

Review before installing. Use only trusted custom templates, run PDF generation in a low-privilege or isolated environment, avoid exposing sensitive environment variables during rendering, and pin the Python dependencies before relying on this in production. Approve the sudo system package install only if you understand the host changes it makes.

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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/render_pdf.py:191
Finding

Unrestricted Custom Jinja Templates Enable Server-Side Template Injection and Arbitrary Resource Fetching

Content
View full analysis

Vulnerability Details

File Location: scripts/render_pdf.py:191-214, with attacker-selectable template handling at scripts/render_pdf.py:220-244
Vulnerability Type: Server-side template injection and unrestricted PDF resource fetching
Risk Level: High

Vulnerable code:

python
def build_environment(template_root: Path):
    from jinja2 import Environment, FileSystemLoader, select_autoescape

    return Environment(
        loader=FileSystemLoader(str(template_root)),
        autoescape=select_autoescape(("html", "xml")),
        trim_blocks=True,
        lstrip_blocks=True,
    )


def render_html(data: dict, template_path: Path) -> str:
    environment = build_environment(template_path.parent)
    template = environment.get_template(template_path.name)
    return template.render(**data)


def write_pdf(html: str, output_path: Path, base_url: str) -> None:
    from weasyprint import HTML

    output_path.parent.mkdir(parents=True, exist_ok=True)
    HTML(string=html, base_url=base_url).write_pdf(str(output_path))

The custom-template option and rendering flow are:

python
parser.add_argument(
    "--template-file",
    help="Optional custom template path inside the workspace",
)
python
template_path = (
    resolve_workspace_path(args.template_file, workspace, must_exist=True)
    if args.template_file
    else default_template
)
html_out_path = (
    resolve_workspace_path(args.html_out, workspace, must_exist=False)
    if args.html_out
    else None
)

payload = normalize_payload(load_payload(input_path), workspace)
html = render_html(payload, template_path)

if html_out_path:
    html_out_path.parent.mkdir(parents=True, exist_ok=True)
    html_out_path.write_text(html, encoding="utf-8")

write_pdf(html, output_path, base_url=str(workspace))

Technical Analysis

The script accepts a caller-selected Jinja template loc ...[truncated 2724 chars]

Remediation
View remediation

Remediation Suggestions

  1. Do not render untrusted custom templates. Disable --template-file by default and require an explicit trusted-template policy when it is enabled.
  2. Replace the standard Jinja environment with jinja2.sandbox.SandboxedEnvironment.
  3. Maintain strict allowlists for permitted filters, tests, globals, and template constructs. Remove unnecessary default globals and reject access to private or dangerous attributes.
  4. Consider replacing general-purpose Jinja templates with a fixed built-in template and a validated JSON schema.
  5. Add a custom WeasyPrint url_fetcher that permits only workspace-local files whose canonical paths remain under the workspace root.
  6. Reject HTTP, HTTPS, FTP, data, and unsupported URI schemes unless a specific business requirement exists.
  7. If remote resources are required, allowlist exact hosts and ports and block loopback, private, link-local, multicast, and cloud metadata address ranges after DNS resolution. Revalidate redirects and resolved addresses.
  8. Run PDF generation in a low-privilege isolated process or container with a read-only filesystem where possible, no sensitive environment variables, restricted outbound networking, resource limits, and access only to required input and output directories.
  9. Add tests using malicious Jinja attribute-traversal expressions and resource URLs targeting localhost, private addresses, and link-local metadata services.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:22
Finding

Unpinned Runtime Dependencies Create a Non-Reproducible Supply-Chain Risk

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:22
Vulnerability Type: Unpinned third-party dependencies
Risk Level: Medium

Vulnerable code:

bash
~/.openclaw/workspace/.venv_pdf/bin/pip install weasyprint jinja2

Technical Analysis

The documented installation command retrieves weasyprint, jinja2, and their transitive dependencies without fixed versions, integrity hashes, or a dependency lock file. Each installation can therefore resolve a different dependency graph based on the package index state at execution time.

No currently malicious package is established by the audited files. The vulnerability is the absence of controls that bind installation to reviewed artifacts. A compromised upstream release, dependency account takeover, malicious transitive release, or unexpected incompatible update could consequently enter the runtime without a corresponding change to this project.

Both packages operate on attacker-influenced content and execute inside the Agent environment, increasing the security importance of deterministic, reviewed dependency versions.

Attack Path

  1. An operator follows the setup instructions and runs the unpinned pip install command.
  2. pip queries its configured package index and resolves the versions available at that time.
  3. A newly released, compromised, or otherwise unreviewed direct or transitive dependency is selected.
  4. Package installation hooks or imported runtime code execute in the environment.
  5. Malicious dependency code can act with the privileges of the installing or rendering process.

Impact Assessment

A compromised dependency may execute arbitrary code during installation or when imported by the renderer. Depending on installation and runtime privileges, it could access workspace data, environment variables, generated reports, network resources, and any files available to the process.

The issue also affects reliability and auditabil ...[truncated 200 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin reviewed direct and transitive dependency versions in a lock file.
  2. Generate and verify cryptographic hashes for every installed artifact, and install with pip's --require-hashes option.
  3. Use a requirements file produced by a reproducible dependency-management process, such as pip-tools, rather than installing unconstrained package names.
  4. Configure an approved package index or internal artifact mirror and prevent unexpected fallback to public or user-controlled indexes.
  5. Regularly scan locked dependencies for known vulnerabilities and update them through a reviewed change process.
  6. Install dependencies as an unprivileged account inside an isolated virtual environment. Do not run the documented pip operation with sudo.
  7. Record the supported Python version and platform-specific dependency versions to improve build reproducibility.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (6)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

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 18)May include surrounding context.

bash
# Ubuntu/Debian
sudo apt-get install -y libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 libffi-dev libcairo2

Create a virtual environment and install Python dependencies (one-time):

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

sudo apt-get install -y libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 libffi-dev libcairo2

text

Create a virtual environment and install Python dependencies (one-time):

```bash
python3 -m venv ~/.openclaw/workspace/.venv_pdf

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The HTML root element hard-codes lang="fr", which indicates the report is intended for French. Under the policy rules, forcing a specific language/locale without user opt-in or clear region-specific justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file describes generating a PDF and notes that output directories are created automatically, but it does not explicitly warn users that running the skill will write a PDF file to the chosen path and may replace an existing file there. Because markdown files should disclose behaviors affecting user data or system state, this is a minor missing-warning issue.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This code performs file-creation operations by generating the output directory and writing PDF and optional HTML output, but it does not present a confirmation prompt or explicit user-facing warning about modifying files. For a code file, file writes can be flagged when there is no visible disclosure in the code and the operation is not otherwise explained beyond argument names.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.