T09 · Insecure Skill Coding Practices
- Location
scripts/yt_auth.py:52- Finding
Unsafe Pickle Deserialization Enables Arbitrary Local Code Execution
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill openly automates social posting, but it needs careful review because it can publish to multiple public accounts from a short command and handles account credentials unsafely.
Install only if you are comfortable giving the skill real posting rights on the connected accounts. Use test accounts first, limit API scopes, review generated content before publishing, avoid the generic all-platform trigger, pin installer and dependency versions, store YouTube tokens outside the project with restrictive permissions, and run video rendering in an isolated environment without production credentials.
scripts/yt_auth.py:52Unsafe Pickle Deserialization Enables Arbitrary Local Code Execution
scripts/yt_auth.py:89YouTube OAuth Credentials Are Persisted Without Restrictive File Protections
scripts/html_video_generator.py:887Chromium Security Sandbox Is Unconditionally Disabled During HTML Rendering
README.md:27Installation Instructions Execute an Unpinned Remote NPM Package
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
"""Make a POST request with retry logic. Returns the post/comment ID."""
for attempt in range(1, MAX_RETRIES + 2):
try:
resp = requests.post(url, params=params, timeout=30)
resp.raise_for_status()
data = resp.json()
post_id = str(data["id"])
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
X_API_KEY=<your X/Twitter API key>
X_API_SECRET=<your X/Twitter API secret>
X_ACCESS_TOKEN=<your X/Twitter access token>
X_ACCESS_TOKEN_SECRET=<your X/Twitter access token secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
X_API_KEY=<your X/Twitter API key>
X_API_SECRET=<your X/Twitter API secret>
X_ACCESS_TOKEN=<your X/Twitter access token>
X_ACCESS_TOKEN_SECRET=<your X/Twitter access token secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
X_API_KEY=<your X/Twitter API key>
X_API_SECRET=<your X/Twitter API secret>
X_ACCESS_TOKEN=<your X/Twitter access token>
X_ACCESS_TOKEN_SECRET=<your X/Twitter access token secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
X_API_KEY=<your X/Twitter API key>
X_API_SECRET=<your X/Twitter API secret>
X_ACCESS_TOKEN=<your X/Twitter access token>
X_ACCESS_TOKEN_SECRET=<your X/Twitter access token secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# ── Paths ─────────────────────────────────────────────────────────────────────
BASE_DIR = Path(__file__).resolve().parent.parent
CLIENT_SECRETS_FILE = BASE_DIR / "client_secrets.json"
TOKEN_FILE = BASE_DIR / "youtube_token.json"
OUTPUT_DIR = BASE_DIR / "output"
LOGS_DIR = BASE_DIR / "logs"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# ── Paths ─────────────────────────────────────────────────────────────────────
BASE_DIR = Path(__file__).resolve().parent.parent
CLIENT_SECRETS_FILE = BASE_DIR / "client_secrets.json"
TOKEN_FILE = BASE_DIR / "youtube_token.json"
OUTPUT_DIR = BASE_DIR / "output"
LOGS_DIR = BASE_DIR / "logs"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# ── Paths ─────────────────────────────────────────────────────────────────────
BASE_DIR = Path(__file__).resolve().parent.parent
CLIENT_SECRETS_FILE = BASE_DIR / "client_secrets.json"
TOKEN_FILE = BASE_DIR / "youtube_token.json"
OUTPUT_DIR = BASE_DIR / "output"
LOGS_DIR = BASE_DIR / "logs"
The README prominently advertises fully automatic posting, scheduling, and multi-platform publishing but does not clearly warn users that the skill can take actions on external accounts using stored credentials. In this context, missing safety disclosure is especially dangerous because users may enable automation without understanding that posts, comments, and scheduled actions can be sent autonomously to public-facing accounts.
Using npx clawhub install social-autopilot without a pinned version or integrity control allows whatever package is current at install time to be executed on the user's system. In a skill that automates posting and likely handles API keys for external accounts, a compromised or swapped package could steal credentials, alter behavior, or perform unauthorized actions during installation.
The trigger phrase Post now is short, generic, and likely to occur in normal conversation, increasing the chance of accidental invocation. Because this skill performs external side effects by publishing content to social platforms, unintended activation could cause unauthorized or embarrassing posts across linked accounts.
The invocation description allows a single ambiguous command to perform a high-impact action across X, Instagram, YouTube, and Meta without any documented confirmation or scoping. In context, this is more dangerous because the skill is fully autonomous and connected to multiple posting backends, so one mistaken invocation can create widespread public actions immediately.
The invocation description allows a single ambiguous command to perform a high-impact action across X, Instagram, YouTube, and Meta without any documented confirmation or scoping. In context, this is more dangerous because the skill is fully autonomous and connected to multiple posting backends, so one mistaken invocation can create widespread public actions immediately.
The documentation claims the content database 'stays local' and is 'never uploaded anywhere,' but the skill explicitly uses CSV-derived content to generate posts, threads, captions, and videos that are then sent to X, Instagram, YouTube, Meta, and Cloudflare R2. This is a misleading data-handling statement that can cause operators to underestimate what information leaves the local environment and accidentally publish sensitive or proprietary dataset contents.
The manifest states that the skill automatically posts to X, Instagram, YouTube, and Facebook, but it does not present a user-facing warning that it can take real actions on connected third-party accounts or process account-linked data. This omission is dangerous because users may enable the skill without understanding that it can publish content externally, potentially causing account abuse, policy violations, data leakage, or reputational harm.
The manifest advertises 'full autopilot' social media behavior and 'Complete social media automation' across multiple external platforms without defining trigger boundaries, approval requirements, or operational limits. In an agent ecosystem, this creates a real risk of unintended autonomous posting, spammy behavior, reputational damage, or misuse of linked accounts because users are not clearly warned about when and how actions will occur.
The top-level description states the formatter is "English only," which is a natural-language locale restriction. Under the policy, forcing a specific language without user opt-in or a documented region-specific justification is a violation.
This Python file embeds multiple user-facing strings such as "UPSC ka sabse bada pattern", "Practice karo", and similar Hindi/English mixed phrases that determine the generated video output. Because the skill does not offer any user opt-in or language selection, it effectively forces a specific language/locale style, which matches the natural-language locale policy violation criteria.
The docstring states the function builds a 3-phase timer challenge with a 5-second countdown and a 5-second answer reveal totaling about 12 seconds. In code, the function appends only a 7-second hook screen and a 3-second CTA screen, with no countdown frames and no answer reveal, so the documented intent materially contradicts the actual behavior.
This code performs external POST requests that create media containers, publish reels, and post comments to Instagram, which can affect the user's public account and transmit content and access tokens over the network. While the code logs status internally, there is no confirmation prompt, docstring, or comment warning the user that these account-modifying actions will be performed.
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.
for attempt in range(1, max_retries + 1):
try:
logger.info("Uploading %s to R2 (attempt %d/%d)", key, attempt, max_retries)
client.upload_file(
str(file_path),
R2_BUCKET,
key,
The code deserializes TOKEN_FILE with pickle.load(), which can execute arbitrary code during unpickling if the token file is attacker-controlled or has been tampered with. In this context the file stores OAuth credentials, so compromise of the token path, CI workspace, or local filesystem could turn a simple credential load into code execution inside the agent environment.
try:
# Try pickle format first (local development)
with open(TOKEN_FILE, "rb") as token:
credentials = pickle.load(token)
except (pickle.UnpicklingError, EOFError):
# Fall back to JSON format (GitHub Actions)
logger.info("Pickle failed, trying JSON format")
The top-level documentation describes this file as an uploader for YouTube Shorts, which implies upload-only behavior. However, the module also defines comment_on_video and post_short logic that posts a top-level comment containing the answer/explanation, which is a materially different action affecting video interactions.
The docstring for format_question_post states 'Zero hashtags' for formatted X/Twitter posts, but the function unconditionally calls _add_x_hashtags for non-quiz days, which appends '#UPSC' and sometimes a second hashtag. This is an active contradiction between the documented intent and runtime behavior.
The docstring says the description includes a 'site link,' but the templates interpolate BRAND_URL, which is not defined anywhere in this file. As written, the function does not reliably implement the documented behavior of producing a real link-containing description.
No suspicious patterns detected.