Back to skill

Security audit

HeyGen Video Agent

Security checks for vulnerabilities and agentic risk

Overview

The plugin’s core HeyGen video-generation behavior is coherent, but its agent-driven install instructions expose API-key handling and mutable remote setup risks that users should review before installing.

Review before installing. Prefer the local bundled install instructions over the README prompt that fetches from GitHub main, use OpenClaw's private onboarding flow for the HeyGen API key, do not paste the key into an agent chat or print it with echo, and rotate the key if it was exposed in logs or transcripts. Only enable default-provider settings and webhook callbacks if you understand their account and data-flow impact.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
INSTALL_FOR_AGENTS.md:41
Finding
Agent-driven installation workflow exposes the HeyGen API key to conversation logs and terminal history<![CDATA[ ## Vulnerability Details **File Location**: `INSTALL_FOR_AGENTS.md:41-47, 77-89, 193-197`; related bootstrap instruction at `README.md:28` **Vulnerability Type**: Sensitive credential exposure through agent-visible input and terminal output **Risk Level**: Medium ### Vulnerable Code Snippet ```markdown ## Step 2: Get the user's HeyGen API key Ask the user for their HeyGen API key. They get it from [app.heygen.com/settings/api](https://app.heygen.com/settings/api) (Settings → API → New Key). Tell them: *the key is shown once, copy it before closing the modal.* ``` The guide subsequently recommends handling the secret in the shell: ```bash # Env-var path (faster, agent-friendly): export HEYGEN_API_KEY=hg_... # Or config-file path: openclaw onboard --auth-choice heygen-api-key ``` During troubleshooting, it recommends printing the credential: ```markdown Check `~/.openclaw/openclaw.json` for `plugins.entries.heygen.auth.apiKey`, or `echo $HEYGEN_API_KEY` in the same shell that started the gateway. ``` The README initiates this workflow with: ```text Read https://raw.githubusercontent.com/heygen-com/openclaw-plugin-heygen/main/INSTALL_FOR_AGENTS.md and follow it. Ask me for any API keys you need. ``` ### Technical Analysis The installation workflow explicitly tells an AI agent to ask the user for the complete HeyGen API key. Secrets supplied through an agent conversation can be retained in conversation history, application telemetry, model-provider logs, debugging traces, or orchestration records. The `echo $HEYGEN_API_KEY` troubleshooting instruction creates another unnecessary disclosure channel by writing the complete secret to terminal output. Depending on the host, terminal output may also be captured by the agent, CI logs, session recording, or centralized logging. This exceeds minimum privilege because the agent does not need to read or reproduce the secret. The existing interactive command, `openclaw onboard --auth-choice heygen-api-k ...[truncated 1539 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all instructions asking users to paste API keys into an agent conversation. 2. Replace the README bootstrap text with wording such as: ```text Never request or display the API key. Ask the user to enter it privately through the OpenClaw authentication prompt. ``` 3. Make the interactive onboarding mechanism the preferred setup path: ```bash openclaw onboard --auth-choice heygen-api-key ``` 4. Remove `echo $HEYGEN_API_KEY` from troubleshooting guidance. 5. Troubleshoot only whether a value is configured, without displaying it. Use an OpenClaw command that reports configuration status in redacted form. 6. If environment-variable setup remains documented, instruct the user to configure it outside the agent session through a secret manager or private terminal. 7. Ensure configuration inspection automatically redacts `plugins.entries.heygen.auth.apiKey`. 8. Recommend immediate key revocation and rotation if a key has already been pasted into chat or printed in recorded terminal output. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
video-generation-provider.ts:458
Finding
Generated video downloads are buffered without a response-size limit<![CDATA[ ## Vulnerability Details **File Location**: `video-generation-provider.ts:458-474` **Vulnerability Type**: Unbounded memory consumption from a remote response **Risk Level**: Medium ### Vulnerable Code Snippet ```ts async function downloadHeyGenVideo(params: { url: string; timeoutMs?: number; fetchFn: typeof fetch; policy: HeyGenTransportPolicy; }): Promise<GeneratedVideoAsset> { const { response, release } = await fetchWithTimeoutGuarded( params.url, { method: "GET" }, params.timeoutMs ?? DEFAULT_TIMEOUT_MS, params.fetchFn, buildGuardedGetOptions({ policy: params.policy, auditContext: "heygen-video-file-download", }), ); try { await assertOkOrThrowHttpError(response, "HeyGen generated video download failed"); const mimeType = normalizeOptionalString(response.headers.get("content-type")) ?? "video/mp4"; const arrayBuffer = await response.arrayBuffer(); const ext = mimeType.includes("webm") ? "webm" : "mp4"; return { buffer: Buffer.from(arrayBuffer), mimeType, fileName: `video-1.${ext}`, metadata: { sourceUrl: params.url }, }; } finally { await release(); } } ``` ### Technical Analysis The function calls `response.arrayBuffer()`, causing the complete remote response body to be accumulated in process memory before it is converted to a Node.js `Buffer`. Although the download uses a timeout and guarded-fetch policy, neither control limits the number of bytes that can be returned within the permitted interval. The function also does not validate `Content-Length`, enforce a streaming byte counter, or apply a maximum generated-asset size. The video URL originates from the HeyGen API response. Exploitation therefore requires a compromised or malicious upstream service, a trusted endpoint override controlled by an attacker, or another condition that causes the API to return an attacker-controlled asset URL. This is not an unrestricted user-supplied do ...[truncated 1358 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define a conservative maximum generated-video size appropriate for the declared five-minute limit. 2. Reject responses whose declared `Content-Length` exceeds that limit. 3. Do not rely exclusively on `Content-Length`, because it can be omitted or falsified. 4. Read `response.body` as a stream and maintain a cumulative byte count. 5. Abort the request and release resources immediately when the cumulative limit is exceeded. 6. Prefer streaming the response to a controlled output sink rather than buffering the complete video in memory. 7. Validate the final content type against an allowlist such as `video/mp4` and `video/webm`. 8. Preserve the existing guarded-fetch and deadline controls; response-size enforcement should be added in addition to them. 9. Add tests for oversized declared lengths, chunked oversized responses, missing lengths, invalid MIME types, and cleanup after an aborted download. ]]>

T03 · Remote Payload Retrieval and Execution

Note
Location
README.md:24
Finding
Installation behavior is delegated to mutable instructions from an unpinned remote branch<![CDATA[ ## Vulnerability Details **File Location**: `README.md:24-32` **Vulnerability Type**: Mutable remote payload retrieval used to direct agent-executed installation actions **Risk Level**: Low ### Vulnerable Code Snippet ```markdown ## Install **Paste this into your OpenClaw agent.** It does the rest — installs the plugin, asks for your HeyGen API key, runs a verify test, and ends with a working video. ``` Read https://raw.githubusercontent.com/heygen-com/openclaw-plugin-heygen/main/INSTALL_FOR_AGENTS.md and follow it. Ask me for any API keys you need. ``` That's it. The agent fetches [INSTALL_FOR_AGENTS.md](./INSTALL_FOR_AGENTS.md) and walks the rest of the install. Same prompt forever — the install spec lives in the repo, not in your clipboard. ``` ### Technical Analysis The README instructs an AI agent to retrieve installation instructions from the mutable `main` branch and follow them. The remotely retrieved document directs the agent to run local commands, install packages, modify configuration, restart the gateway, and handle credentials. Because the URL is not pinned to a release tag, immutable commit, or verified digest, its content can change after the package has been audited. A compromise of the upstream repository or a malicious future modification can therefore alter the effective installation payload without changing the locally reviewed Skill version. The currently bundled `INSTALL_FOR_AGENTS.md` did not contain malicious shell commands, persistence mechanisms, SSH-key access, or privilege-escalation behavior. The risk arises from delegating future executable agent behavior to mutable remote content. ### Attack Path 1. An attacker compromises the upstream repository account, branch protections, or publishing workflow. 2. The attacker modifies `INSTALL_FOR_AGENTS.md` on the `main` branch to include malicious installation instructions. 3. A user copies the stable bootstrap prompt from the README into an agent. 4. The agent fetches ...[truncated 1186 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not instruct agents to execute installation directions from a mutable branch. 2. Prefer the installation guide bundled with the installed and reviewed package. 3. If remote retrieval is necessary, pin the URL to an immutable Git commit rather than `main`. 4. Publish and verify a cryptographic digest for the retrieved file. 5. Require explicit user confirmation before each package installation, configuration change, gateway restart, or other state-changing command. 6. Treat retrieved Markdown as untrusted data and restrict it to a documented allowlist of installation operations. 7. Ensure branch protection, mandatory review, signed commits, and release provenance controls are enabled for the upstream repository. 8. Version the installation specification together with the plugin so that reviewers can evaluate the exact instructions users will execute. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (25)

Known Vulnerable Dependency: undici==7.25.0 — 12 advisory(ies): CVE-2026-6733 (undici vulnerable to HTTP response queue poisoning via keep-alive socket reuse); CVE-2026-13697 (undici vulnerable to cross-user information disclosure and parse-time crash via ); CVE-2026-16728 (undici vulnerable to downstream response desynchronization via retry interceptor) +9 more

High
Category
Supply Chain
Confidence
89% confidence
Finding
undici 7.25.0 is listed with multiple high-severity advisories including response desynchronization, queue poisoning, and possible cross-user information disclosure. Because this plugin is network-centric and interacts with external APIs through the OpenClaw ecosystem, a vulnerable HTTP client in the dependency tree is more concerning than in a purely local tool, even if the affected copy is transitive.

Known Vulnerable Dependency: @mariozechner/pi-coding-agent==0.70.2 — 3 advisory(ies): CVE-2026-54326 (Pi Agent: Potential XSS in HTML session exports via Markdown URL sanitization by); CVE-2026-54328 (Pi Agent: Predictable temporary extension install paths allow local privilege es); CVE-2026-54327 (Pi Agent: Race condition in Pi auth.json writes could expose stored credentials)

High
Category
Supply Chain
Confidence
84% confidence
Finding
@mariozechner/pi-coding-agent 0.70.2 is flagged for multiple advisories involving XSS in session exports, predictable temporary extension paths, and credential exposure via auth.json race conditions. These are genuine risks in the bundled agent framework, although they are not specific to the HeyGen plugin itself and their impact depends on whether the host environment uses those coding-agent features.

Known Vulnerable Dependency: basic-ftp==5.3.0 — 1 advisory(ies): CVE-2026-44240 (basic-ftp allows a malicious FTP server to cause client-side denial of service v)

High
Category
Supply Chain
Confidence
80% confidence
Finding
basic-ftp 5.3.0 is flagged for a malicious-server-triggered client-side denial of service. This is a real issue, but in this plugin it appears transitively through networking tooling rather than core HeyGen functionality, so the main risk is to environments that may interact with attacker-controlled FTP endpoints through shared agent infrastructure.

Known Vulnerable Dependency: brace-expansion==5.0.5 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-45149 (brace-expansion: Large numeric range defeats documented `max` DoS protection); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
81% confidence
Finding
brace-expansion 5.0.5 has multiple DoS advisories related to exponential or unbounded expansion. This is a real dependency vulnerability; while often only exploitable when attacker-controlled glob or pattern input is processed, agent ecosystems frequently consume user-supplied paths or patterns, so the broader host context increases concern somewhat.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The instructions direct the agent to collect, set, and persist a HeyGen API key via environment variables or OpenClaw config, but they do not warn against echoing, logging, or displaying the secret back to the user. In an agent-executed workflow, this increases the risk of inadvertent secret exposure through command history, terminal output, screenshots, logs, or later config inspection.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The troubleshooting guidance tells the agent/user to inspect `~/.openclaw/openclaw.json` and `echo $HEYGEN_API_KEY`, both of which can reveal the raw secret in terminal output, agent transcripts, logs, or shared sessions. This is a real secret-exposure risk because the file is explicitly agent-facing and may be followed verbatim by automation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README instructs the agent to fetch and follow remote installation instructions from a raw GitHub URL and to ask the user for API keys, effectively delegating trusted setup steps to mutable external content. This creates a supply-chain and prompt-injection risk: the remote INSTALL_FOR_AGENTS.md can change after review and could instruct the agent to exfiltrate credentials, install unsafe components, or perform additional actions outside the reviewed repository content.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill documentation explicitly describes sending prompts, avatar IDs, voice IDs, and optional callback data to HeyGen's external API, but it does not provide a clear user-facing warning about that outbound data transfer. This can mislead users into submitting sensitive scripts, identity-linked avatar metadata, or internal webhook identifiers without realizing they are leaving the local/OpenClaw environment and being processed by a third party.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The documentation encourages use of a `callback_url` webhook but does not warn that HeyGen will send job status and correlation metadata to an external endpoint. In a plugin centered on generated videos tied to identities, this can cause users to expose internal endpoints, identifiers, or workflow metadata to third parties without understanding the privacy and trust implications.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The docs mention `incognito_mode` only as an opt-out of server-side logging, but they do not clearly state that logging may occur by default when the option is omitted. Because this provider handles scripts, presenter identity choices, and potentially branded or sensitive content, users may unknowingly submit confidential material under a default retention/logging posture they did not expect.

External Transmission

Medium
Category
Data Exfiltration
Content
expect(postJsonRequestMock).toHaveBeenCalledWith(
      expect.objectContaining({
        url: "https://api.heygen.com/v3/video-agents",
        body: expect.objectContaining({
          prompt: "Welcome new agents to HeyGen.",
          avatar_id: "avatar_demo_1",
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
expect(postJsonRequestMock).toHaveBeenCalledWith(
      expect.objectContaining({
        url: "https://api.heygen.com/v3/video-agents",
        body: expect.objectContaining({
          prompt: "Welcome new agents to HeyGen.",
          avatar_id: "avatar_demo_1",
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
expect(postJsonRequestMock).toHaveBeenCalledWith(
      expect.objectContaining({
        url: "https://api.heygen.com/v3/video-agents",
        body: expect.objectContaining({
          prompt: "Welcome new agents to HeyGen.",
          avatar_id: "avatar_demo_1",
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
expect(postJsonRequestMock).toHaveBeenCalledWith(
      expect.objectContaining({
        url: "https://api.heygen.com/v3/video-agents",
        body: expect.objectContaining({
          prompt: "Welcome new agents to HeyGen.",
          avatar_id: "avatar_demo_1",
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
expect(postJsonRequestMock).toHaveBeenCalledWith(
      expect.objectContaining({
        url: "https://api.heygen.com/v3/video-agents",
        body: expect.objectContaining({
          prompt: "Welcome new agents to HeyGen.",
          avatar_id: "avatar_demo_1",
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
expect(postJsonRequestMock).toHaveBeenCalledWith(
      expect.objectContaining({
        url: "https://api.heygen.com/v3/video-agents",
        body: expect.objectContaining({
          prompt: "Welcome new agents to HeyGen.",
          avatar_id: "avatar_demo_1",
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
expect(postJsonRequestMock).toHaveBeenCalledWith(
      expect.objectContaining({
        url: "https://api.heygen.com/v3/video-agents",
        body: expect.objectContaining({
          prompt: "Welcome new agents to HeyGen.",
          avatar_id: "avatar_demo_1",
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Known Vulnerable Dependency: @anthropic-ai/sdk==0.90.0 — 1 advisory(ies): CVE-2026-41686 (Claude SDK for TypeScript has Insecure Default File Permissions in Local Filesys)

Low
Category
Supply Chain
Confidence
76% confidence
Finding
The lockfile pins @anthropic-ai/sdk 0.90.0, which is flagged for insecure default file permissions in local filesystem operations. In a dependency manifest this is a genuine supply-chain exposure, though the practical risk to this HeyGen plugin is limited unless the plugin or its host actually invokes the affected SDK functionality to write sensitive local files.

Known Vulnerable Dependency: @hono/node-server==1.19.14 — 1 advisory(ies): GHSA-frvp-7c67-39w9 (Node.js Adapter for Hono: Path traversal in `serve-static` on Windows via encode)

Low
Category
Supply Chain
Confidence
70% confidence
Finding
@hono/node-server 1.19.14 is reported vulnerable to Windows path traversal in serve-static handling. This is a real issue in the dependency version, but for this skill's context it appears only as a transitive package in the broader OpenClaw stack and there is no evidence in this file that the plugin exposes static file serving on Windows, so exploitability here is limited.

Known Vulnerable Dependency: @protobufjs/utf8==1.1.0 — 1 advisory(ies): CVE-2026-44288 (protobufjs has overlong UTF-8 decoding)

Low
Category
Supply Chain
Confidence
66% confidence
Finding
@protobufjs/utf8 1.1.0 has an advisory for overlong UTF-8 decoding, which is a legitimate dependency weakness. In this skill context it is only a transitive library and there is no direct indication that attacker-controlled protobuf parsing is exposed, so the practical security impact here is low.

Known Vulnerable Dependency: @vitest/mocker==2.1.9 — 1 advisory(ies): CVE-2026-84373 (Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock)

Low
Category
Supply Chain
Confidence
72% confidence
Finding
@vitest/mocker 2.1.9 is vulnerable to path traversal/arbitrary file read, but it is a dev-only testing dependency. This makes it a real vulnerability in the supply chain, yet generally low risk for production use of the HeyGen plugin unless untrusted users can run the test harness or CI in a shared environment.

Known Vulnerable Dependency: body-parser==2.2.2 — 1 advisory(ies): CVE-2026-12590 (body-parser vulnerable to denial of service when invalid limit value silently di)

Low
Category
Supply Chain
Confidence
67% confidence
Finding
body-parser 2.2.2 is reported vulnerable to denial of service on invalid limit handling. This is a genuine issue in the pinned version, but in this lockfile it is transitive and there is no evidence that this plugin directly exposes an Express endpoint processing attacker-controlled bodies, so the immediate risk is limited.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"typecheck": "tsc --noEmit"
  },
  "devDependencies": {
    "typescript": "^5.6.0",
    "vitest": "^2.1.0"
  },
  "peerDependencies": {
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "devDependencies": {
    "typescript": "^5.6.0",
    "vitest": "^2.1.0"
  },
  "peerDependencies": {
    "openclaw": ">=2026.3.24-beta.2"
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Missing User Warnings

Low
Confidence
76% confidence
Finding
This test exercises video generation that posts prompts and provider options to the HeyGen API and then downloads generated media, but the file contains no user-facing warning, comment, or disclosure about external transmission of prompt/media data. Under the code-file criteria, network operations that transmit user or system data should have some visible disclosure unless clearly covered elsewhere; that warning is not present in this file.

Static analysis

No suspicious patterns detected.