T09 · Insecure Skill Coding Practices
- Location
INSTALL_FOR_AGENTS.md:41- Finding
Agent-driven installation workflow exposes the HeyGen API key to conversation logs and terminal history
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
INSTALL_FOR_AGENTS.md:41Agent-driven installation workflow exposes the HeyGen API key to conversation logs and terminal history
video-generation-provider.ts:458Generated video downloads are buffered without a response-size limit
README.md:24Installation behavior is delegated to mutable instructions from an unpinned remote branch
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.
@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.
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.
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.
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.
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.
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.
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.
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.
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.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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",
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.
@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.
@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.
@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.
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.
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"typescript": "^5.6.0",
"vitest": "^2.1.0"
},
"peerDependencies": {
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.
},
"devDependencies": {
"typescript": "^5.6.0",
"vitest": "^2.1.0"
},
"peerDependencies": {
"openclaw": ">=2026.3.24-beta.2"
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.