Back to skill

Security audit

Dual-Host Daily Podcast Generator

Security checks for vulnerabilities and agentic risk

Overview

The skill is aligned with podcast generation, but it combines automated public publishing, S3 feed mutation, external TTS transmission, and cron scheduling with insufficient safeguards.

Review before installing or automating. Use only a dedicated S3 bucket and least-privilege AWS credentials, add a manual approval step before public publishing, avoid confidential or copyrighted source text, fix the Fish API key handling, and harden the RSS update script before running it from cron.

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

Warning
Location
scripts/generate_episode.sh:37
Finding

Predictable Shared Temporary File Allows Local File Overwrite and Feed Corruption

Content
View full analysis
/dev/null # 3. Build new item PUBDATE=$(date -d "${DATE}" -u '+%a, %d %b %Y 08:00:00 +0800') BUILDDATE=$(date -u '+%a, %d %b %Y %H:%M:%S +0000') NEW_ITEM="\n ${TITLE}\n ${DESC}\n \n ${PUBDATE}\n ${DURATION}\n ${DESC}\n \n podcast-${DATE}-${EP_LOWER}\n " # 4. Insert new item after line and update build date sed -i "s|.*|${BUILDDATE}\n\n ${NEW_ITEM}|" /tmp/feed_current.xml # 5. Upload updated RSS aws s3 cp /tmp/feed_current.xml "s3://${BUCKET}/feed.xml" --content-type "application/rss+xml" ``` ### Technical Analysis The script uses the fixed, globally predictable path `/tmp/feed_current.xml` without securely creating the file, checking its ownership, or verifying that it is a regular file rather than a symbolic link. On a multi-user system, another local user can create this path before the script runs. Depending on the behavior and permissions of the invoked tools, the subsequent S3 download or in-place `sed` operation may follow or otherwise interact unsafely with an attacker-created symbolic link. The effect is influenced by operating-system and tool-level symlink protections, but the code itself does not establish a safe invariant. The same fixed path is also shared by every invocation. Concurrent cron jobs or manual runs c ...[truncated 1666 chars]
Remediation
View remediation
&2 exit 1 } trap 'rm -rf -- "$TMPDIR_PATH"' EXIT FEED_FILE="$TMPDIR_PATH/feed.xml" aws s3 cp "s3://${BUCKET}/feed.xml" "$FEED_FILE" ``` Additional hardening should include: 1. Use the unique `$FEED_FILE` path for all subsequent processing and uploads. 2. Set a restrictive process umask, such as `umask 077`, before creating temporary files. 3. Verify that the downloaded object is a regular file before modifying it. 4. Avoid globally writable shared paths for security-sensitive intermediate data. 5. Add locking around feed updates so concurrent executions cannot overwrite each other. 6. Consider an S3-side concurrency control strategy, such as validating the previous object version or ETag before uploading the modified feed. 7. Run the publishing job under a dedicated, unprivileged service account with access only to the required podcast objects. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_episode.sh:43
Finding

Unescaped Episode Metadata Permits RSS and sed Replacement Injection

Content
View full analysis
\n ${TITLE}\n ${DESC}\n \n ${PUBDATE}\n ${DURATION}\n ${DESC}\n \n podcast-${DATE}-${EP_LOWER}\n " # 4. Insert new item after line and update build date sed -i "s|.*|${BUILDDATE}\n\n ${NEW_ITEM}|" /tmp/feed_current.xml ``` ### Technical Analysis The caller-supplied `TITLE` and `DESC` values are inserted directly into XML text nodes without XML escaping. Values containing characters such as `&`, `<`, or `>` can make the feed invalid or terminate the intended element and insert new XML elements. The generated XML is then embedded directly into a `sed` replacement expression delimited by `|`. Replacement-sensitive characters, including `|`, `&`, and backslashes, are not escaped. In a `sed` replacement, `&` represents the entire matched text, while delimiter and backslash sequences can alter or invalidate the expression. Because shell syntax is parsed before parameter expansion, this construction does not by itself demonstrate shell command execution. The confirmed issue is injection into the generated RSS document and manipulation or failure of the `sed` expression. ### Attack Path 1. An attacker gains control over, or persuades an operator to use, a crafted episode title or description. 2. The crafted value includes XML closing tags and additional RSS elements, or characters meaningful to a `sed` repl ...[truncated 1218 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/fish_dual_tts.py:9
Finding

Documented Environment Credential Is Ignored, Encouraging API Key Storage in Source

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents an end-to-end automated podcast generation and publishing skill. The supplied code chunk implements only one narrow subtask: dual-voice TTS synthesis from an existing script using the Fish Audio API. It does not fetch content, write the conversation, publish artifacts, manage RSS feeds, or schedule execution. There is no evidence of S3 access, Apple/Spotify integration, or Edge TTS support in this chunk. Because the actual behavior is a materially smaller and different subset than the declared primary purpose, the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 106)May include surrounding context.

md
bash scripts/generate_episode.sh <date> <EP-number> <title> <description> <mp3-file>

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill describes network access, file access, external API use, and publishing behavior, but it does not declare any explicit tool scope or permissions boundaries. This is dangerous because an agent may be granted broader-than-necessary capabilities by default, increasing the risk of unintended web access, local file reads, or publishing actions without clear operator review.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill directs the operator to fetch web content and send scripts to third-party TTS services, but it does not warn that scraped text, prompts, and generated dialogue may be transmitted to external providers. This is dangerous because users may unknowingly send copyrighted, confidential, or sensitive material to outside services, and the podcast context increases exposure by combining external ingestion with automated republication.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill instructs users to publish audio, RSS metadata, and distribute content through messaging channels, but it does not warn that this may expose generated content, feed metadata, episode titles/descriptions, or operator identity information publicly. In this context, the skill is specifically designed for automated public distribution, so missing disclosure and review warnings materially increase the chance of accidental data leakage or reputational harm.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/fish_dual_tts.py (reported line 10)May include surrounding context.

python
import sys, os, json, requests, tempfile

API_KEY = "YOUR_FISH_API_KEY"
API_URL = "https://api.fish.audio/v1/tts"

VOICES = {
    "HostA": "YOUR_VOICE_A_ID",  # Voice A

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/fish_dual_tts.py (reported line 42)May include surrounding context.

python
return segments

def tts(text, voice_id, output):
    resp = requests.post(API_URL,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code posts the provided script content to the Fish Audio API, which transmits user-supplied text off-system. Although the script prints progress and errors, it does not disclose beforehand that input content will be sent to a third-party service, and the module docstring also omits that warning.

Content

No source excerpt is available for this finding.

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.

Content

Scanner excerpt · scripts/generate_episode.sh (reported line 36)May include surrounding context.

sh
# 1. Upload MP3
echo "☁️ Uploading ${S3_KEY}..."
aws s3 cp "$MP3_FILE" "s3://${BUCKET}/${S3_KEY}" --content-type "audio/mpeg"

# 2. Download current RSS
aws s3 cp "s3://${BUCKET}/feed.xml" /tmp/feed_current.xml 2>/dev/null

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.

Content

Scanner excerpt · scripts/generate_episode.sh (reported line 39)May include surrounding context.

sh
# 1. Upload MP3
echo "☁️ Uploading ${S3_KEY}..."
aws s3 cp "$MP3_FILE" "s3://${BUCKET}/${S3_KEY}" --content-type "audio/mpeg"

# 2. Download current RSS
aws s3 cp "s3://${BUCKET}/feed.xml" /tmp/feed_current.xml 2>/dev/null

Cloud Storage Exfiltration

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is uploaded to cloud storage (S3 / GCS / Azure Blob). This may be a legitimate backup or exfiltration to an external bucket. Manual review is recommended.

Content

Scanner excerpt · scripts/generate_episode.sh (reported line 50)May include surrounding context.

sh
# 1. Upload MP3
echo "☁️ Uploading ${S3_KEY}..."
aws s3 cp "$MP3_FILE" "s3://${BUCKET}/${S3_KEY}" --content-type "audio/mpeg"

# 2. Download current RSS
aws s3 cp "s3://${BUCKET}/feed.xml" /tmp/feed_current.xml 2>/dev/null

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The code opens the user-supplied output path in write-binary mode, which will create or overwrite the file. There is no confirmation prompt or documentation note warning the user that the specified output path will be modified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script uses a fixed path (/tmp/feed_current.xml) for downloading and editing the RSS feed, which can be clobbered by concurrent runs or pre-created by another local user/process via symlink or race-condition attacks. In an automated cron-style publishing workflow, this can lead to accidental overwrite, corruption of the feed, or writing sensitive content to an unintended file path.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.