T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/video_podcast.py:181- Finding
Browser authentication cookies are accessed by default
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a real video-to-podcast publisher, but it needs review because it reads browser cookies by default and handles cloud credentials in an overbroad, weakly protected way.
Review before installing. Use a bucket-scoped R2 token, make the R2 bucket public only if you intend the feed and uploaded audio to be public, set VIDPOD_COOKIE_BROWSER=none unless you explicitly need authenticated downloads, keep unrelated secrets out of ~/.openclaw/.env, and restrict that file to owner-only permissions such as 0600.
scripts/video_podcast.py:181Browser authentication cookies are accessed by default
scripts/video_podcast.py:54All secrets in the shared OpenClaw environment file are imported
scripts/video_podcast.py:349Plaintext credentials are written without enforcing restrictive file permissions
SKILL.md:83Security-sensitive third-party dependencies are installed without version or integrity pinning
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
Podcast feed title",
"required": false,
"sensitive": false,
},
{
"key": "VIDPOD_FEED_AUTHOR",
"description": "Podcast author name",
"required": false,
"sensitive": false,
},
{
"key": "VIDPOD_COOKIE_BROWSER",
"description": "Browser to read cookies from for age-restricted/SABR-protected videos (safari, chrome, firefox, or none). Default: safari. Cookies are read locally and never transmitted.",
"required": false,
"sensitive": false,
},
],
"install":
[
{
"id": "ffmpeg",
"kind": "brew",
"package": "ffmpeg",
"bins": ["ffmpeg"],
"label": "Install ffmpeg (audio conversion)",
},
{
"id": "yt-dlp",
"kind": "pip",
"package": "
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# ── Constants ──────────────────────────────────────────────────────────────────
ENV_FILE = Path.home() / ".openclaw" / ".env"
STATE_FILE = Path.home() / ".openclaw" / "video-podcast-state.json"
REQUIRED_ENV = [
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# ── Constants ──────────────────────────────────────────────────────────────────
ENV_FILE = Path.home() / ".openclaw" / ".env"
STATE_FILE = Path.home() / ".openclaw" / "video-podcast-state.json"
REQUIRED_ENV = [
The script reads raw credentials from a plaintext env file in the user's home directory and loads them into process environment variables. While common, this creates avoidable exposure if the file permissions are weak, backups sync the file elsewhere, or other local processes/users can read it.
# ── Env helpers ────────────────────────────────────────────────────────────────
def load_env():
"""Load ~/.openclaw/.env into os.environ."""
if ENV_FILE.exists():
for line in ENV_FILE.read_text().splitlines():
line = line.strip()
The setup flow writes access keys and secrets into ~/.openclaw/.env as plaintext without setting restrictive permissions. Storing long-lived cloud credentials unencrypted on disk increases the risk of local credential theft, accidental disclosure, and reuse against the user's R2 bucket.
ENV_FILE.parent.mkdir(parents=True, exist_ok=True)
ENV_FILE.write_text("\n".join(lines) + "\n")
print("\n✅ Config saved to ~/.openclaw/.env")
print("\nNext: verify ffmpeg is installed:")
print(" brew install ffmpeg (macOS)")
print(" sudo apt install ffmpeg (Linux)")
The skill declares environment-variable, file-read, and file-write capabilities but does not explicitly scope or document allowed tools/permissions. In an agent setting, missing tool boundaries increases the risk of unintended access to local state or secrets and makes security review and runtime enforcement harder.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
brew install ffmpeg # macOS sudo apt install ffmpeg # Linux
### 2. Create a Cloudflare R2 bucket
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
brew install ffmpeg # macOS sudo apt install ffmpeg # Linux
### 2. Create a Cloudflare R2 bucket
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
sudo apt install ffmpeg # Linux
### 2. Create a Cloudflare R2 bucket
1. Sign up at [cloudflare.com](https://cloudflare.com) (free tier is sufficient)
2. Go to **R2 Object Storage** → **Create bucket**
The setup and usage describe enabling public access and hosting feed/media publicly, but the skill description and agent-facing trigger guidance do not clearly warn the user that uploaded audio and feed contents become publicly accessible. This can lead to unintended disclosure of content choices, playlist membership, and derived media.
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.
# Using AWS CLI (if installed)
aws s3 cp cover.jpg s3://podcast-feed/cover.jpg \
--endpoint-url https://<account_id>.r2.cloudflarestorage.com \
--content-type image/jpeg
Several trigger phrases are broad enough to overlap with ordinary conversation, which can cause the agent to invoke the skill when the user did not clearly intend to publish media or modify persistent feed state. Because this skill performs external uploads and persistent state changes, accidental activation has meaningful consequences.
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_type: str, cache_control: str) -> str:
"""Upload a local file to R2. Returns public URL."""
client = r2_client(cfg)
client.upload_file(
local_path,
cfg["bucket"],
key,
The code configures yt-dlp to read cookies directly from a local browser profile via cookiesfrombrowser, which expands the skill's access to sensitive local session material beyond simple video-to-podcast conversion. Even if intended to improve downloads, this can grant access to age-restricted, subscriber-only, or otherwise authenticated content using the user's browser session without an explicit, narrowly scoped consent flow.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
val = input(f"{label}{display}: ").strip()
new_values[key] = val if val else current
# Write back
lines = []
if ENV_FILE.exists():
for line in ENV_FILE.read_text().splitlines():
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
print("\n✅ Config saved to ~/.openclaw/.env")
print("\nNext: verify ffmpeg is installed:")
print(" brew install ffmpeg (macOS)")
print(" sudo apt install ffmpeg (Linux)")
def cmd_add(url: str):
The remove command performs a user-impacting modification by deleting an episode from local state and immediately republishing the RSS feed, but there is no confirmation step before the destructive action. Although there is a post-action print statement, the code lacks prior user disclosure or confirmation for this irreversible feed change.
Skill requests more permissions than appear necessary for its stated functionality. Review if elevated access is justified.
### 3. Create an R2 API token
1. R2 → **Manage R2 API Tokens** → Create token
2. Set permissions: **Object Read & Write** on your bucket
3. Note the **Access Key ID** and **Secret Access Key**
4. Note your **Account ID** from the dashboard top-right
The generated feed always sets the channel language to "en", which imposes a specific locale regardless of user preference or content language. This is a natural-language locale policy concern because the skill does not offer opt-in, configuration, or justification for forcing English.
No suspicious patterns detected.