Back to skill

Security audit

sjht-ppt-delivery

Security checks for vulnerabilities and agentic risk

Overview

This skill is coherent for Feishu PDF delivery, but it should be reviewed because it can send local files using stored Feishu bot credentials and renders HTML with Chromium sandboxing disabled.

Install only if you want agents to send generated presentation files through Feishu. Use a tightly scoped Feishu bot account, confirm the destination user and exact filename before sending, restrict uploads to generated workspace outputs, and avoid rendering untrusted HTML unless Chromium sandboxing or container isolation is added.

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

Error
Location
html2pdf.cjs:42
Finding

Chromium Sandbox Disabled While Rendering Active HTML

Content
View full analysis

Vulnerability Details

File Location: html2pdf.cjs, lines 42–46
Vulnerability Type: Browser sandbox disabled for active HTML rendering
Risk Level: High

Vulnerable Code

javascript
const browser = await puppeteer.launch({
  executablePath: '/usr/bin/chromium-browser',
  headless: true,
  args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage']
});

Technical Analysis

The converter opens HTML in Chromium with JavaScript enabled while explicitly disabling both Chromium's process sandbox and setuid sandbox. The script does not implement request interception, network restrictions, or other isolation controls for the rendered document.

Rendering HTML is required for the declared PDF-conversion functionality, but disabling both sandbox mechanisms exceeds what is necessary. If slide content, embedded scripts, or referenced resources are attacker-controlled, that content executes inside a materially weakened browser security boundary. Remote resources can also be loaded because the page is opened with waitUntil: 'networkidle0' and no outbound-request policy is configured.

Exploitation beyond browser-context behavior would generally require a compatible Chromium vulnerability, but disabling the sandbox increases the consequences of such a vulnerability.

Attack Path

  1. An attacker influences the HTML slide deck or causes it to reference attacker-controlled JavaScript or other active content.
  2. The user or Agent invokes html2pdf.cjs to convert the document.
  3. Chromium loads and executes the active content.
  4. The browser operates with both --no-sandbox and --disable-setuid-sandbox.
  5. The malicious content initiates unintended network activity or exploits a compatible Chromium vulnerability.
  6. A successful browser exploit can escape the renderer without the normal Chromium sandbox barrier and act with the privileges of the account running the Skill.

Impact Assessment

At minimum, attacker-control ...[truncated 462 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove --no-sandbox and --disable-setuid-sandbox, and configure the host so Chromium's supported sandbox can operate.
  2. Run conversion as a dedicated, unprivileged operating-system user with access only to the input file, output directory, Chromium dependencies, and required fonts.
  3. Place each conversion in a short-lived container or equivalent isolation boundary with a read-only root filesystem, dropped Linux capabilities, resource limits, and no access to Agent credentials.
  4. Block outbound network access by default. If remote assets are required, use Puppeteer request interception and an explicit allowlist of trusted schemes and hosts.
  5. Disable JavaScript where slide rendering does not require it. Otherwise, reject unexpected scripts and sanitize untrusted HTML before rendering.
  6. Restrict local navigation and resource loading to the intended input document and approved local assets.
  7. Keep Chromium patched and ensure the Puppeteer/Chromium versions are compatible and maintained.
  8. Close Chromium in a finally block so failures do not leave residual browser processes.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documented behavior claims a full local HTML→PDF pipeline, but the detected behavior is materially different: only Feishu upload/send is evidenced, and it relies on local credential/config access that is not disclosed. This mismatch can mislead operators into granting trust or invoking the skill under false assumptions, hiding the real exfiltration-capable behavior.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill explicitly performs external network actions by uploading and sending files to Feishu, yet it declares no tool scope or permissions boundary. That omission makes the capability less transparent to the orchestrator and reviewers, increasing the risk of unintended data exfiltration or unauthorized outbound actions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are broad and overlap with common requests such as creating slides or sending PDFs, which can cause the skill to activate in situations where the user did not clearly consent to external delivery. In this skill’s context, accidental activation is more dangerous because it culminates in sending a file to a third-party messaging platform.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill instructs uploading and sending a PDF to a Feishu user but provides no explicit user-facing warning or consent checkpoint for external file transmission. Because presentations often contain sensitive business content, silent transmission to an external service materially raises confidentiality and privacy risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script silently reads Feishu bot credentials from ~/.openclaw/openclaw.json and immediately uses them to authenticate and send files externally. In an agent skill context, this can enable unintended use of locally scoped secrets to transmit data without explicit user awareness or consent, increasing the risk of secret misuse and unauthorized messaging.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
77% confidence
Finding

This duplicate external-transmission finding correctly identifies outbound transmission of sensitive authentication material to Feishu. Although the endpoint is legitimate, the security concern remains that local secrets are automatically used by the skill in a way that may not be transparent to the end user.

Content

Scanner excerpt · send_file_feishu.py (reported line 70)May include surrounding context.

python
mime_type = ext_map.get(ext, file_type)

# 1. Get tenant_access_token
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
    json={"app_id": APP_ID, "app_secret": APP_SECRET})
token = r.json().get("tenant_access_token")
if not token:

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

This duplicate external-transmission finding correctly identifies outbound transmission of sensitive authentication material to Feishu. Although the endpoint is legitimate, the security concern remains that local secrets are automatically used by the skill in a way that may not be transparent to the end user.

Content

Scanner excerpt · send_file_feishu.py (reported line 70)May include surrounding context.

python
mime_type = ext_map.get(ext, file_type)

# 1. Get tenant_access_token
r = requests.post("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
    json={"app_id": APP_ID, "app_secret": APP_SECRET})
token = r.json().get("tenant_access_token")
if not token:

External Transmission

Medium
Category
Data Exfiltration
Confidence
92% confidence
Finding

The script uploads an arbitrary local file specified by file_path to Feishu. In an agent skill, if an upstream prompt, tool, or workflow can influence file_path, this becomes a direct data exfiltration path for sensitive local files, and the skill's stated purpose makes that risk more acute rather than incidental.

Content

Scanner excerpt · send_file_feishu.py (reported line 83)May include surrounding context.

python
content_type = mime_types.get(mime_type, "application/octet-stream")

with open(file_path, "rb") as f:
    r = requests.post("https://open.feishu.cn/open-apis/im/v1/files",
        headers=headers,
        data={"file_type": mime_type, "file_name": file_name},
        files={"file": (file_name, f, content_type)})

Tainted flow: 'headers' from requests.post (line 78, network input) → requests.post (network output)

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 · send_file_feishu.py (reported line 83)May include surrounding context.

python
content_type = mime_types.get(mime_type, "application/octet-stream")

with open(file_path, "rb") as f:
    r = requests.post("https://open.feishu.cn/open-apis/im/v1/files",
        headers=headers,
        data={"file_type": mime_type, "file_name": file_name},
        files={"file": (file_name, f, content_type)})

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This duplicate finding correctly captures the final outbound transmission step to an external messaging recipient. Combined with file upload at line 83, it enables end-to-end exfiltration of generated or arbitrary local files to a remote user, which is highly sensitive for an automation skill whose primary role is document delivery.

Content

Scanner excerpt · send_file_feishu.py (reported line 95)May include surrounding context.

python
print(f"File uploaded: {file_key}")

# 3. Send file message
r = requests.post(
    "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id",
    headers={**headers, "Content-Type": "application/json"},
    json={

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This duplicate finding correctly captures the final outbound transmission step to an external messaging recipient. Combined with file upload at line 83, it enables end-to-end exfiltration of generated or arbitrary local files to a remote user, which is highly sensitive for an automation skill whose primary role is document delivery.

Content

Scanner excerpt · send_file_feishu.py (reported line 95)May include surrounding context.

python
print(f"File uploaded: {file_key}")

# 3. Send file message
r = requests.post(
    "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id",
    headers={**headers, "Content-Type": "application/json"},
    json={

Tainted flow: 'headers' from requests.post (line 78, network input) → requests.post (network output)

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 · send_file_feishu.py (reported line 95)May include surrounding context.

python
print(f"File uploaded: {file_key}")

# 3. Send file message
r = requests.post(
    "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id",
    headers={**headers, "Content-Type": "application/json"},
    json={

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The skill names and trigger phrases are presented in Chinese only, and the documentation does not indicate that users may interact in other languages or choose their preferred locale. This can constitute a language-policy issue if the organization expects skills not to force a specific language without opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.