Back to skill

Security audit

Beamer Pipeline Public

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Beamer deck pipeline, but it needs Review because it automatically fetches remote document images and includes under-disclosed OpenClaw session/artifact recovery code that can scan shared local directories.

Install only if you are comfortable running it on trusted papers or in a sandboxed environment. Use --skip-assets for untrusted Markdown, prefer an explicit --agent-cmd/--no-agent workflow, and avoid relying on run_agent_role.js recovery behavior unless you have reviewed and constrained its access to ~/.openclaw and prior task outputs.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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/prepare_task_assets.js:47
Finding
Automatic image localization permits server-side request forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/prepare_task_assets.js`, lines 47-64 and 92-113 **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```javascript function extractMarkdownImages(text) { const matches = []; const regex = /!\[([^\]]*)\]\((https?:\/\/[^\s)]+)(?:\s+"[^"]*")?\)/g; let match; let order = 0; while ((match = regex.exec(text)) !== null) { order += 1; matches.push({ order, alt: String(match[1] || "").trim(), url: String(match[2] || "").trim(), source_excerpt: String(match[0] || "").slice(0, 240), }); } return matches; } ``` ```javascript async function fetchBuffer(url) { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), 60000); try { const response = await fetch(url, { redirect: "follow", signal: controller.signal, headers: { "user-agent": "openclaw-pipeline/prepare-task-assets", }, }); if (!response.ok) { throw new Error(`http ${response.status}`); } const arrayBuffer = await response.arrayBuffer(); return { buffer: Buffer.from(arrayBuffer), contentType: response.headers.get("content-type") || "", finalUrl: response.url || url, }; } finally { clearTimeout(timer); } } ``` The public runner invokes asset preparation automatically unless the user supplies `--skip-assets`. ### Technical Analysis Any HTTP or HTTPS URL embedded using Markdown image syntax is fetched from the machine running the skill. The implementation does not validate the destination hostname or resolved IP address before making the request. Consequently, an untrusted paper or Markdown document can cause requests to: - Loopback services such as `127.0.0.1` or `[::1]`. - Private network ranges. - Link-local services, including cloud metadata endpoints. - Internal DNS names unavailable to the document author. - Service ...[truncated 1919 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse every URL with `new URL()` and allow only explicitly approved protocols and destinations. 2. Resolve hostnames before connecting and reject all loopback, private, link-local, multicast, unspecified, reserved, and carrier-grade NAT address ranges for both IPv4 and IPv6. 3. Revalidate the hostname and resolved addresses after every redirect. Prefer `redirect: "manual"` and implement a small, bounded redirect loop. 4. Block common metadata hostnames and addresses, including link-local metadata endpoints, as defense in depth. 5. Consider making remote asset downloads opt-in rather than automatic for untrusted documents. 6. Provide a hostname allowlist option for controlled deployments. 7. Run asset retrieval in a sandbox without access to internal networks or cloud metadata. 8. Do not pass downloaded content to an agent until its type and integrity have been validated. 9. Add automated tests covering direct private addresses, DNS rebinding, IPv4-mapped IPv6 addresses, encoded IP formats, and public-to-private redirects. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/prepare_task_assets.js:92
Finding
Unbounded remote response buffering enables memory and disk exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/prepare_task_assets.js`, lines 92-113 and 199-213 **Vulnerability Type**: Uncontrolled Resource Consumption **Risk Level**: Medium ### Vulnerable Code ```javascript async function fetchBuffer(url) { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), 60000); try { const response = await fetch(url, { redirect: "follow", signal: controller.signal, headers: { "user-agent": "openclaw-pipeline/prepare-task-assets", }, }); if (!response.ok) { throw new Error(`http ${response.status}`); } const arrayBuffer = await response.arrayBuffer(); return { buffer: Buffer.from(arrayBuffer), contentType: response.headers.get("content-type") || "", finalUrl: response.url || url, }; } finally { clearTimeout(timer); } } ``` ```javascript if (!cachePath || !fs.existsSync(cachePath)) { const fetched = await fetchBuffer(asset.url); finalUrl = fetched.finalUrl; fileSha = sha256(fetched.buffer); ext = inferExt(finalUrl, fetched.contentType); cachePath = path.join(cacheDir, `${urlHash}_${fileSha.slice(0, 12)}${ext}`); fs.writeFileSync(cachePath, fetched.buffer); writeJson(urlMetaPath, { url: asset.url, final_url: finalUrl, url_hash: urlHash, file_sha256: fileSha, ext, cache_path: cachePath, task_scope: taskScope, }); } ``` ### Technical Analysis The downloader calls `response.arrayBuffer()`, which buffers the complete response in memory before any size validation occurs. There is no limit on: - The declared `Content-Length`. - The number of bytes read from the response stream. - The aggregate size of all downloaded images. - The number of image URLs processed. - The resulting cache or figures directory size. The 60-second timeout limits request duration but does not impose a byte limit. A fast server can transmit a very large response with ...[truncated 1688 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a conservative per-file byte limit before and during download. 2. Reject responses whose `Content-Length` exceeds the configured limit, while treating a missing header as untrusted rather than safe. 3. Read `response.body` incrementally and abort immediately when the actual byte count exceeds the limit. 4. Set aggregate limits for the number of remote assets and total bytes downloaded per task. 5. Stream approved responses to a temporary file instead of buffering the entire body in memory. 6. Delete partial files when downloads fail or exceed limits. 7. Validate file signatures and permit only required image formats; do not save arbitrary `.bin` responses as successful assets. 8. Limit redirect count and include redirect responses in the same byte and time budget. 9. Apply filesystem quotas or run asset preparation in a resource-constrained sandbox. 10. Record rejected oversized assets in the manifest without retaining their bodies. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/run_agent_role.js:7497
Finding
Artifact recovery scans broad OpenClaw and session directories without strong task isolation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run_agent_role.js`, lines 7420-7438, 7497-7560, and 7831-7874 **Vulnerability Type**: Cross-task local artifact discovery and unintended file access **Risk Level**: Medium ### Vulnerable Code ```javascript function walkFiles(rootPath, maxDepth, visitor, depth = 0) { if (!rootPath || depth > maxDepth) return; let entries = []; try { entries = fs.readdirSync(rootPath, { withFileTypes: true }); } catch { return; } for (const entry of entries) { const fullPath = path.join(rootPath, entry.name); if (entry.isDirectory()) { walkFiles(fullPath, maxDepth, visitor, depth + 1); continue; } if (entry.isFile()) { visitor(fullPath); } } } ``` ```javascript function buildArtifactSearchRoots(state, transcriptPath, mode, payload = null) { const candidateRoots = new Set(); const transcriptDir = transcriptPath ? path.dirname(transcriptPath) : ""; const compatRoots = mode === "beamer" ? [ path.join(os.homedir(), ".openclaw", "beamer_outputs"), path.join(os.homedir(), ".openclaw", "leankan_beamer_package"), path.join(os.homedir(), ".openclaw", "media", "outbound"), ] : [ path.join(os.homedir(), ".openclaw", "ppt_output"), path.join(os.homedir(), ".openclaw", "media", "outbound"), ]; // ... if (transcriptDir) { candidateRoots.add(transcriptDir); } if (!restrictToTaskSpecificRoots) { for (const compatRoot of compatRoots) { candidateRoots.add(compatRoot); } } ``` ```javascript function findBeamerArtifactBundle(state, transcriptPath, payload = null) { const { roots, missingRoots, taskSpecificRoots } = buildArtifactSearchRoots(state, transcriptPath, "beamer", payload); // ... for (const root of roots) { walkFiles(root, 4, (fullPath) => { ``` The dispatcher also derives the transcript location from the user's home directory: ```javascript function r ...[truncated 3191 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require one explicit, canonical output directory in every payload and restrict all artifact discovery to that directory. 2. Remove the session transcript directory and shared compatibility directories from artifact search roots. 3. If backward compatibility is required, make shared-root recovery an explicit opt-in operation that displays the selected directory to the user. 4. Bind each artifact bundle to a task identifier or checkpoint key stored inside a signed or trusted manifest. 5. Verify that every discovered path resolves beneath the canonical task directory using `fs.realpathSync()` and a separator-aware containment check. 6. Reject symlinks or verify their resolved targets before reading or writing. 7. Do not infer ownership from filenames, timestamps, or bundle completeness alone. 8. Separate transcript monitoring from artifact discovery; reading the current session transcript should not authorize scanning its parent directory. 9. Prevent recovery helpers from mutating a bundle until ownership and output-directory validation have completed. 10. Update documentation to accurately disclose any remaining session access and compatibility-root behavior. 11. Add regression tests with multiple task bundles in shared directories to ensure that one task can never recover or modify another task's files. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (39)

Ae1

High
Category
analysis-evasion
Content
- Added `run_agent_role.js` with shared agent-role dispatch logic (programmer/reviewer/tester).
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- Added `run_agent_role.js` with shared agent-role dispatch logic (programmer/reviewer/tester).
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- Enhanced `deck_language_render_guards.js` for output language constraints.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- Enhanced `deck_language_render_guards.js` for output language constraints.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/run_beamer_public.js --input paper.md --out out --dry-run
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/run_beamer_public.js --input paper.md --out out --dry-run
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/run_beamer_public.js --input paper.md --out out --dry-run
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/run_beamer_public.js --input paper.md --out out --dry-run
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/run_beamer_public.js --input paper.md --out out --dry-run
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `--skip-assets`: skip `prepare_task_assets.js`.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `--skip-assets`: skip `prepare_task_assets.js`.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/deck_equation_coverage_repair.js`: repairs unresolved equation coverage entries.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/deck_notation_coverage_repair.js`: repairs missing or inconsistent notation coverage.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/deck_strategy_placeholder_repair.js`: replaces strategy placeholders with concrete content.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/deck_equation_coverage_scanner.js`: scans for equation coverage gaps.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/deck_symbol_canonicalization.js`: shared symbol canonicalization helper.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/slide_schema.js`: shared slide/equation block normalization helper.
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
"For final-phase PPT tasks, add these additional structured acceptance fields to the same top-level JSON object: render_status, validation_status, pptx_warnings, layout_policy, visible_prose_recovery_hint, visible_prose_fidelity_final, render_fidelity_safeguards.",
    "render_status must concretely state whether main.pptx was generated, which renderer command was used, where logs live if any, and what blocker/warning summary remains.",
    "validation_status must summarize pptx_validation.json with ok/fatal_count/warning_count and the concrete report path.",
    "pptx_warnings must preserve validator warning facts from pptx_validation.json issues/warnings; use warning_count=0 plus a summary when there are no warnings.",
    "layout_policy.overfull_assessment must classify PPT layout/render warnings into none/minor/moderate/severe and choose gate_decision=pass/repair/fail accordingly.",
    "visible_prose_recovery_hint is a non-gating recovery/debug hint and may stay partial or sampled.",
    "visible_prose_fidelity_final must be the full-deck gating audit with status pass|warning|fail, full checked slide IDs, checked_slide_count, total_slide_count, coverage_ratio, uncovered_source_segments, and omitted_by_design.",
Confidence
80% confidence
Finding
Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The description states the skill converts papers into a Chinese academic Beamer deliverable, which imposes a specific language output by default. The file does not present this as an optional or user-selectable locale, so it appears to force a language choice without opt-in.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
These lines require Chinese academic presentation style and faithful Chinese translations as part of the generated deck contract. That is a natural-language locale constraint, and no nearby text indicates user opt-in or an alternative language mode.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The validation-token builder injects Chinese phrases such as "编译状态", "可读性", "原始 TeX 告警", and similar locale-specific terms directly into the token set. This imposes a specific language/locale expectation in natural-language handling without any visible user choice or documented justification in this code file.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
This JavaScript file embeds user-facing natural-language phase titles and goals entirely in Chinese, such as "分析" and other Chinese descriptions, while providing no opt-in, fallback, or explanation that the skill is intended only for Chinese-language users. Under the policy, forcing a specific language without user choice is a natural-language locale violation.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The error message explicitly requires rewriting content 'in Chinese', and similar checks throughout the file enforce that visible prose should be Chinese. This is a natural-language locale constraint embedded in the skill logic, but the file does not show any user choice or documented opt-in for that language requirement.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
This diagnostic message states that visible Beamer prose 'should be Chinese', which indicates a hard-coded language policy. Under the policy, forcing a specific language without user opt-in is a violation unless the locale constraint is clearly justified.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The rendered-text validation flags mostly-English lines because visible prose 'should be Chinese'. This is another explicit fixed-language requirement with no evidence in the file of user choice or narrowly justified locale scope.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/deck_notation_coverage_repair.js:46

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/run_agent_role.js:2543

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/run_beamer_public.js:137