Back to skill

Security audit

Podcast Production Pipeline

Security checks for vulnerabilities and agentic risk

Overview

The skill is a plausible podcast workflow, but it ships real-looking secrets and can automatically send episode metadata to Discord without clear opt-in.

Review before installing. Do not use this package with confidential guest names, unreleased topics, or private transcripts unless the credentials are removed, the gateway token is deleted, Discord posting is made explicit and opt-in, and all API keys are supplied by your own secure configuration. Any exposed keys should be considered compromised and rotated.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
config/settings.json:29
Finding
Plaintext Third-Party API Credentials Distributed with the Skill<![CDATA[ ## Vulnerability Details **File Location**: `config/settings.json:29-33` **Vulnerability Type**: Hardcoded third-party API credentials **Risk Level**: High ### Vulnerable Code ```json "apis": { "tavily": "tvly-dev-[REDACTED]", "gemini": "AIzaSy[REDACTED]", "elevenlabs": "sk_[REDACTED]" } ``` The credential values have been redacted from this report to prevent further disclosure. The audited file contains the complete plaintext values. ### Technical Analysis The distributed configuration contains live-looking credentials for Tavily, Google Gemini, and ElevenLabs. These secrets are available to anyone who can download or inspect the Skill package. The Tavily credential is actively referenced by `scripts/podcast-pre-production.cjs`, where it is placed in the request body sent to the Tavily search endpoint. The Gemini and ElevenLabs credentials are not used by the audited scripts, but their plaintext exposure remains independently exploitable. Embedding credentials in a distributable package violates secret-management and least-exposure principles. Removing the keys in a later revision is insufficient if they have already been published because package archives, caches, forks, and version-control history may retain them. ### Attack Path 1. An attacker downloads or otherwise obtains the Skill package. 2. The attacker opens `config/settings.json`. 3. The attacker extracts the plaintext Tavily, Gemini, and ElevenLabs credentials. 4. The attacker submits authenticated requests directly to the corresponding providers. 5. The attacker consumes account quotas, incurs costs, or accesses any APIs and account data authorized for those credentials. No execution of the Skill is required to exploit this issue. ### Impact Assessment An attacker may obtain the third-party API privileges granted to the exposed credentials. The precise scope depends on provider-side permissions and account configuration, but potential consequences include: - Unauthoriz ...[truncated 418 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Immediately revoke and rotate all three exposed credentials. 2. Review provider logs for unauthorized use beginning from the earliest publication date. 3. Remove credentials from the current package, repository history, releases, caches, examples, and generated artifacts. 4. Replace committed values with nonfunctional placeholders. 5. Load secrets from explicitly configured environment variables or a supported secret manager. 6. Validate that required secrets are present at runtime and fail closed when they are absent. 7. Grant each replacement credential only the minimum API permissions and spending limits needed. 8. Use separate credentials for development, testing, and production. 9. Add automated secret scanning to development and release pipelines. 10. Prevent configuration files containing real credentials from being included in published packages. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/podcast-pre-production.cjs:187
Finding
Hardcoded OpenClaw Gateway Bearer Token Used as an Authentication Fallback<![CDATA[ ## Vulnerability Details **File Location**: `scripts/podcast-pre-production.cjs:187-211` **Vulnerability Type**: Hardcoded local gateway authentication token **Risk Level**: High ### Vulnerable Code ```js async function sendToDiscord(message) { return new Promise((resolve, reject) => { const token = process.env.OPENCLAW_GATEWAY_TOKEN || 'b8cb95b2fb220c2896a44dc6514f47ef4efed792bcd07c3f'; const postData = JSON.stringify({ channel: 'discord', action: 'send', channelId: config.discord_channel, message: message, silent: true }); const options = { hostname: '127.0.0.1', port: 18789, path: '/api/v1/tools/message', method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, 'Content-Length': Buffer.byteLength(postData) } }; const req = http.request(options, (res) => { ``` ### Technical Analysis The script embeds a reusable bearer token and uses it whenever `OPENCLAW_GATEWAY_TOKEN` is absent. Anyone able to inspect the package can recover the fallback token without executing the script. The token authenticates requests to the local OpenClaw gateway endpoint `/api/v1/tools/message`. Although the demonstrated request sends a Discord message, the effective impact depends on the gateway permissions associated with the token and whether the same credential is accepted by other gateway endpoints. The request is transmitted using plaintext HTTP. Loopback transport reduces exposure to remote network interception, but it does not protect the credential from local traffic inspection, debugging proxies, compromised local processes, or a malicious service bound to the expected port. A hardcoded fallback also causes the software to continue silently with a shared credential rather than failing safely when runtime authentication is not configured. ### Attack Path 1. An attacker obtains the Skill source o ...[truncated 1383 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke the embedded gateway token immediately and investigate its use. 2. Delete the hardcoded fallback from all source, release, and history locations. 3. Require an explicitly supplied runtime secret and terminate safely if it is absent. 4. Store the replacement token in an operating-system secret store or another approved secret manager. 5. Issue a narrowly scoped token that can access only the required messaging action and destination. 6. Do not reuse the token across unrelated gateway tools or environments. 7. Apply short expiration periods and automated token rotation. 8. Enforce server-side authorization per endpoint, action, channel, and destination. 9. Prefer a protected local transport, such as a permission-restricted Unix-domain socket, or use authenticated TLS where applicable. 10. Avoid logging tokens or complete authorization headers. 11. Add gateway audit logging and alert on unexpected endpoints, channels, or request volumes. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/podcast-pre-production.cjs:187
Finding
Automatic Disclosure of Episode and Guest Metadata to a Configured Discord Channel<![CDATA[ ## Vulnerability Details **File Location**: `scripts/podcast-pre-production.cjs:187-205,246-256` **Vulnerability Type**: Unconditional external transmission of user-supplied metadata **Risk Level**: Medium ### Vulnerable Code ```js async function sendToDiscord(message) { return new Promise((resolve, reject) => { const token = process.env.OPENCLAW_GATEWAY_TOKEN || 'b8cb95b2fb220c2896a44dc6514f47ef4efed792bcd07c3f'; const postData = JSON.stringify({ channel: 'discord', action: 'send', channelId: config.discord_channel, message: message, silent: true }); const options = { hostname: '127.0.0.1', port: 18789, path: '/api/v1/tools/message', method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, 'Content-Length': Buffer.byteLength(postData) } }; ``` ```js // 构建 Discord 消息 const discordMessage = `🎙️ **Episode ${episodeNumber} 前期制作完成!** 📝 **话题**: ${topic} ${guestName ? `👤 **嘉宾**: ${guestName}` : ''} ✅ 已生成节目大纲和采访问题 📁 **文件**: \`${path.basename(outlinePath)}\``; // 发送到 Discord 线程 await sendToDiscord(discordMessage); ``` ### Technical Analysis After pre-production succeeds, the script automatically sends a message containing the user-supplied episode number, topic, optional guest name, and generated filename to the Discord channel configured by `config.discord_channel`. The transmission is part of the default execution path. There is no command-line opt-in, confirmation prompt, privacy warning, per-run destination verification, or local-only default. While the documentation references Discord configuration and a changelog entry mentions Discord delivery, it does not clearly explain that every normal pre-production run automatically transmits these specific fields. Podcast planning information can be confidential before publication. A topic or guest name may reveal embargoed content, unrelea ...[truncated 1690 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make Discord delivery explicitly opt-in, such as through a `--send-discord` flag. 2. Default to local-only output. 3. Before sending, display the destination and exact fields to be transmitted and request confirmation in interactive use. 4. Provide a documented noninteractive consent setting for automation. 5. Validate the configured channel against an administrator-controlled allowlist. 6. Do not ship a real channel identifier as a package default. 7. Allow users to select or redact individual metadata fields. 8. Treat guest names and unreleased topics as potentially sensitive data. 9. Record auditable delivery results without logging credentials or unnecessary content. 10. Clearly document the data destination, transmitted fields, retention implications, and method for disabling integration. 11. Separate file generation from external publishing so that a successful local workflow never inherently requires Discord transmission. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (22)

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README shows use of external APIs (`tavily`, `gemini`) and workflows involving guest research and transcript processing, but it does not warn users that podcast topics, guest names, and transcript contents may be sent to third-party services. This creates a real privacy and data-handling risk because users may process unpublished content or personal data without informed consent or awareness of external transmission.

Lp3

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding
The skill advertises execution of Node scripts and references API keys/configuration, but it does not declare any explicit tool scope or permissions boundary. In a skill that performs research and transcript processing, undeclared environment or tool access increases the chance of over-broad execution, secret exposure, or unintended file/system access by the hosting agent.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The description and all user-facing instructions are written in Chinese, effectively forcing a single language for the skill experience. There is no opt-in language selection or explicit documentation that the skill is intentionally limited to a Chinese-speaking or China-specific audience.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill processes guest research data and episode transcripts, which may contain personal data, sensitive opinions, or unpublished content, yet the description provides no privacy or data-handling warning. Users may unknowingly submit third-party personal information or confidential recordings to external APIs, creating compliance, consent, and data leakage risks.

Natural-Language Policy Violations

Medium
Confidence
85% confidence
Finding
The `host_name` value is set to `繁哥`, which indicates a specific language/locale presentation baked into the skill configuration. For a general-purpose skill config, this can create a language/locale policy issue because users are not offered a choice or opt-in to that locale-specific output.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The natural-language description is entirely in Chinese and emphasizes domestic-platform adaptation, which suggests a fixed language/locale orientation without any indication that users can choose another language. This may violate language/locale policy when the skill appears to assume a specific language by default rather than offering opt-in or documenting a justified regional restriction.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The file header presents this as a usable 'Podcast Post-Production Pipeline', but the implementation of later generators depends on undeclared variables such as guestName and topic, causing runtime failure before outputs are produced. This is an active contradiction between the script's documented purpose/usage and what the code can actually do.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file uses Chinese-language usage text and later formats dates/times with the fixed 'zh-CN' locale and Asia/Shanghai timezone, indicating the skill is designed to operate in a single language/locale. The file does not offer opt-in or a configurable locale, which matches the policy concern for forcing a specific language or locale without user choice.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The manifest describes an end-to-end podcast production pipeline with research, outline generation, show notes, and social promotion support, but this file's actual behavior is limited to creating local markdown templates. Although it reads a transcript file, the transcript is never used to derive notes, descriptions, highlights, or platform-adapted content, so the implemented behavior falls short of the claimed automation.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The generated output uses toLocaleDateString('zh-CN') and similar fixed locale/timezone calls elsewhere, which forces Chinese localization regardless of user preference. Because no user-selectable locale or documented regional limitation is present, this is a natural-language locale policy issue.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This output template embeds a fixed Chinese locale and Shanghai timezone for generated timestamps. Hard-coding a locale in user-facing content without offering a choice or documenting a justified regional scope violates the stated natural-language locale policy.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This template forces Chinese localization and Shanghai timezone for output metadata. The skill does not provide any mechanism for users to select another language or locale, so it enforces a specific locale by default.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The generated social-media package includes metadata localized only for zh-CN and Asia/Shanghai. Without opt-in or a documented regional requirement, this is an avoidable language/locale policy issue.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This template again fixes output to Chinese locale and Shanghai timezone, making the skill's user-facing content locale-specific with no choice for users. That matches the natural-language policy concern around forced locale behavior.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
User-provided topic and guest information are sent to Tavily for external research without explicit notice or consent. In a podcast workflow this may seem normal, but guest identities or unreleased episode topics can be sensitive, so silent transfer to a third-party service creates privacy and confidentiality risk.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The script performs an outbound side effect by posting episode status/details to Discord, but that behavior is outside the core local pre-production flow and is not clearly disclosed by the stated scope. Undisclosed external messaging increases data exposure risk because topics, guest names, and workflow metadata are transmitted to another system without explicit user consent or a clearly bounded trust model.

Context-Inappropriate Capability

Medium
Confidence
99% confidence
Finding
The code includes a hardcoded fallback bearer token for a local messaging gateway, which is a credential exposure issue and enables unauthorized use of that gateway if the script or repository is shared. Even though the endpoint is localhost, embedded secrets are dangerous because they can be reused by other local processes or attackers with code access, and they normalize hidden privileged capabilities unrelated to the main research function.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script sends generated episode details, including topic and possibly guest name, to Discord without clear upfront disclosure. This creates an unnecessary external dissemination path for potentially embargoed production information, especially risky in media workflows where episode plans and guest participation may be confidential until publication.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
Most user-facing instructions and descriptions are provided only in Chinese, which effectively forces a specific language for users of the skill. The file does not offer an alternative language option or explain that the skill is intentionally limited to a Chinese-language audience.

Vague Triggers

Low
Confidence
82% confidence
Finding
The package description presents a very broad end-to-end automation capability covering multiple podcast-production tasks, but it does not define any specific trigger phrases, scope boundaries, or exclusion conditions. In a manifest context, this kind of broad natural-language description can contribute to unintended invocation because it overlaps with many common podcast-related requests.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The natural-language interface and usage text are presented in Chinese, and the script later formats time using the zh-CN locale, but there is no indication that this is optional or required for a region-specific purpose. This can violate language/locale policy when a skill forces a specific language without user opt-in.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The generated outline always uses the zh-CN locale and Asia/Shanghai timezone for its timestamp. This is a locale-specific behavior that is not presented as configurable or justified as region-specific, which may conflict with organizational language/locale policy.

Static analysis

Detected: suspicious.env_credential_access, suspicious.potential_exfiltration

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/podcast-pre-production.cjs:189

File read combined with network send (possible exfiltration).

Warn
Code
suspicious.potential_exfiltration
Location
scripts/podcast-pre-production.cjs:13