Back to skill

Security audit

Youtube Description Autoposter

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly transparent about generating and posting YouTube timestamps, but it can automatically modify live YouTube descriptions and caches reusable credentials in an unsafe way.

Install only if you are comfortable granting YouTube write access and having the tool automatically append AI-generated timestamps to public video descriptions. Prefer running generation-only first, manually reviewing the output and target video, storing OAuth tokens outside the project with restrictive permissions, replacing pickle token storage, and using a safer secret path than passing the Gemini key as a command argument.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/youtube_desc_generator.py:174
Finding

Untrusted LLM Output Can Be Published Without Validation or Confirmation

Content
View full analysis

Vulnerability Details

File Location: scripts/youtube_desc_generator.py:174-186, 243-260
Vulnerability Type: Indirect prompt injection and unsafe use of generated content
Risk Level: High

Vulnerable Code

python
Transcript:
{formatted_transcript}

Important Formatting Notes:
- Put the PRIMARY KEYWORD or a variation of it in the FIRST timestamp (0:00)
- Include MAJOR PRODUCT NAMES as keywords naturally (e.g., Google Flow, Veo 3.1, Nano Banana 2)
- End with a CONCLUSION or FINAL THOUGHTS timestamp
- Keep each description under 8 words for scannability
"""

genai.configure(api_key=api_key)
model = genai.GenerativeModel('gemini-3.1-flash-lite-preview')

timestamps = model.generate_content(timestamp_prompt).text
python
if args.post:
    youtube = get_authenticated_service()

    if target_video_id:
        # URL mode — post to the specified video
        title, current_desc = get_video_details(youtube, target_video_id)
        print(f"\nTarget video: {title} ({target_video_id})")
    else:
        # File mode — post to latest upload
        target_video_id, title, current_desc = get_latest_video(youtube)
        print(f"\nLatest video: {title} ({target_video_id})")

    # Append timestamps to the bottom of the current description
    new_description = current_desc.strip() + f"\n\n{timestamps}"

    # Proceed directly without manual confirmation
    update_video_description(youtube, target_video_id, new_description)

Technical Analysis

Raw transcript content is interpolated directly into the Gemini prompt without delimiting it as untrusted data or defending against embedded instructions. The transcript can originate from user input or remotely retrieved YouTube captions.

The generated response is then treated as trusted timestamp content. The implementation does not verify that every line is a chapter entry, that timestamps are ordered and within the video ...[truncated 1406 chars]

Remediation
View remediation

Remediation Suggestions

  • Treat transcripts and model responses as untrusted data.
  • Delimit transcript content clearly and instruct the model that text inside the delimiter must never be interpreted as instructions.
  • Parse the response using a strict allowlist grammar, such as one timestamp and one short plain-text label per line.
  • Reject unexpected lines, URLs, markup, control characters, excessive lengths, or content that does not begin with 0:00.
  • Verify that timestamps are ordered, unique, within the video's duration, and separated by at least ten seconds.
  • Display the exact target video and a complete diff of the proposed description.
  • Require explicit interactive confirmation before calling videos().update().
  • Provide a non-interactive override only when the caller explicitly requests it and all validation succeeds.
  • Consider keeping generation and publication as separate commands to preserve a human review boundary.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/youtube_desc_generator.py:35
Finding

Unsafe Deserialization of OAuth Credentials Through Pickle

Content
View full analysis

Vulnerability Details

File Location: scripts/youtube_desc_generator.py:35-39
Vulnerability Type: Arbitrary code execution through unsafe deserialization
Risk Level: High

Vulnerable Code

python
creds = None
if os.path.exists(TOKEN_PICKLE):
    with open(TOKEN_PICKLE, 'rb') as token:
        creds = pickle.load(token)

Technical Analysis

Python Pickle is an executable serialization format. Loading a Pickle can invoke attacker-selected constructors and reduction functions before the returned object is inspected. Consequently, pickle.load() must only be used with data whose integrity and provenance are guaranteed.

The token is loaded from a predictable file inside the project directory. No ownership, permissions, file type, symlink, signature, or integrity checks are performed before deserialization. An attacker who can write to that path does not need valid Google credentials; a crafted Pickle can execute code as soon as an authenticated operation calls get_authenticated_service().

Attack Path

  1. An attacker gains write access to the project directory or convinces the user to copy a malicious token.pickle into scripts/.
  2. The attacker constructs a Pickle whose deserialization routine runs a command or imports malicious Python code.
  3. The user invokes --latest or uses --post.
  4. get_authenticated_service() finds the file and calls pickle.load().
  5. The embedded payload executes with the operating-system privileges of the user running the Skill.

Impact Assessment

Exploitation provides arbitrary local code execution in the user's security context. The attacker could read or alter accessible files, steal API and OAuth credentials, modify project code, access authenticated services, or perform any other operation permitted to that user. This risk exceeds the credential-caching needs of the Skill.

Remediation
View remediation

Remediation Suggestions

  • Replace Pickle with Google credential JSON serialization, such as Credentials.to_json() and the corresponding safe JSON loader.
  • Store tokens in a private per-user configuration directory rather than inside the project.
  • Verify that the token is a regular file owned by the current user and is not a symbolic link.
  • Open the file using protections against symlink following where supported.
  • Validate the expected JSON schema and required credential fields before use.
  • If migration support is required, do not automatically load legacy Pickle files. Require explicit user action to remove them and reauthenticate.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/youtube_desc_generator.py:48
Finding

OAuth Token Is Written Without Explicit Access-Control Protections

Content
View full analysis

Vulnerability Details

File Location: scripts/youtube_desc_generator.py:48-53
Vulnerability Type: Insecure storage of sensitive OAuth credentials
Risk Level: Medium

Vulnerable Code

python
flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_FILE, SCOPES)
creds = flow.run_local_server(port=0)
with open(TOKEN_PICKLE, 'wb') as token:
    pickle.dump(creds, token)

Technical Analysis

The cached credential includes authorization sufficient to perform YouTube operations using the youtube.force-ssl scope. The file is created using ordinary open() and therefore relies on the process umask for confidentiality. The implementation does not explicitly enforce owner-only permissions, use atomic replacement, reject symbolic links, or place the file in a private credential directory.

On a shared or permissively configured system, another local account may be able to read the token. If the containing directory is writable, an attacker may also replace or redirect the file. Replacement is particularly severe because the application later deserializes it with Pickle.

Attack Path

  1. The user completes the OAuth flow.
  2. The script creates scripts/token.pickle under the permissions determined by the current umask.
  3. On a permissive or shared installation, another local user reads the file or replaces it.
  4. A stolen token is used to access authorized YouTube operations, or a replacement Pickle is triggered during a later run.

Impact Assessment

Disclosure may expose reusable OAuth credentials capable of operating on the user's YouTube account within the granted scope. Replacement may lead to local code execution because of the unsafe deserialization behavior. The exact exposure depends on directory ownership, umask, token validity, and local multi-user access.

Remediation
View remediation

Remediation Suggestions

  • Store credentials in an operating-system credential store or a private per-user configuration directory.
  • Create the directory with owner-only access and the token file with mode 0600.
  • Write credentials to a new private file, flush and synchronize it, and atomically rename it into place.
  • Refuse to read or write through symbolic links.
  • Verify file ownership and permissions each time the token is loaded.
  • Use a safe non-executable serialization format rather than Pickle.
  • Document token revocation and cleanup procedures, and avoid placing credentials within a repository checkout.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/youtube_desc_generator.py:198
Finding

Gemini API Key Is Passed Through the Process Argument List

Content
View full analysis

Vulnerability Details

File Location: scripts/youtube_desc_generator.py:198-203
Vulnerability Type: Sensitive credential exposure through command-line arguments
Risk Level: Medium

Vulnerable Code

python
source.add_argument('--latest', action='store_true', help='Process your latest video automatically and check for existing timestamps')

parser.add_argument('gemini_api_key', help='Gemini API key')
parser.add_argument('--post', action='store_true', help='Automatically post the generated timestamps to YouTube')
args = parser.parse_args()

The documented invocation also expands the secret into the child process argument list:

bash
python scripts/youtube_desc_generator.py --url "https://youtu.be/abc123" "$GEMINI_API_KEY"

Technical Analysis

Requiring an API key as a positional command-line argument exposes its value through operating-system process metadata. Depending on the platform and configuration, command arguments may be visible to other local processes or users. Arguments may also be retained in shell history, terminal capture, process-monitoring systems, debugging output, automation logs, or agent execution records.

Quoting or expanding an environment variable in the shell does not address this issue: after expansion, the actual key is still included in the new process's argument vector.

Attack Path

  1. The user follows the documented command and supplies the Gemini key as the positional argument.
  2. The shell expands the variable into the command's argument vector.
  3. A local process monitor, another permitted local user, or an execution-logging system records the arguments.
  4. The attacker extracts the key and reuses it against the Gemini API.

Impact Assessment

A disclosed key can be used to consume the victim's API quota, incur charges where billing is enabled, access API functionality associated with the key, or cause service disruption through quota exha ...[truncated 121 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove the positional API-key argument.
  • Read the key from a dedicated environment variable inside Python, without passing it as an argument.
  • Prefer an operating-system secret store or managed secret service for automated environments.
  • Offer an interactive no-echo prompt through getpass.getpass() when no configured secret is available.
  • Ensure exceptions and debug logs never include the key.
  • Update all examples in README.md and SKILL.md so they do not place secrets in the process argument list.
  • Rotate any key that may already have been exposed through logs or process monitoring.

T08 · Insecure Dependencies

Warning
Location
README.md:8
Finding

Third-Party Dependencies Are Installed Without Version or Integrity Pinning

Content
View full analysis

Vulnerability Details

File Location: README.md:8-11
Vulnerability Type: Uncontrolled dependency resolution and supply-chain exposure
Risk Level: Medium

Vulnerable Code

bash
pip install youtube-transcript-api google-generativeai google-auth-oauthlib google-api-python-client

The same installation pattern appears in SKILL.md:15.

Technical Analysis

The setup instructions install multiple packages without exact versions, hashes, or a lock file. Each installation can therefore resolve to different package and transitive-dependency versions over time. A compromised upstream release, an unexpectedly incompatible release, or a malicious transitive package could be installed and imported with the user's privileges.

The package names appear consistent with the imports found in the implementation; the audit did not identify a confirmed typosquatted package. The risk arises from mutable, unverified dependency resolution rather than evidence that the currently named packages are malicious.

Attack Path

  1. An upstream package or transitive dependency publishes a compromised release, or a future release introduces a security regression.
  2. A user follows the unpinned pip install instructions.
  3. Pip resolves the new release because no reviewed version or hash is required.
  4. Installation hooks or imported package code execute in the user's environment.
  5. The malicious or vulnerable dependency gains the same access as the Skill process, including access to supplied credentials and transcript data.

Impact Assessment

A compromised dependency may execute arbitrary code during installation or runtime. It could access local files, capture Gemini and OAuth credentials, alter generated content, or manipulate YouTube API operations. The ultimate scope is limited by the privileges of the user and environment in which installation and execution occur.

Remediation
View remediation

Remediation Suggestions

  • Create a reviewed dependency lock file with exact package and transitive-dependency versions.
  • Use hash verification, such as pip install --require-hashes, for reproducible installation.
  • Install dependencies in an isolated virtual environment under a non-privileged user.
  • Regularly scan locked dependencies for known vulnerabilities and review updates before adoption.
  • Record the supported Python version and dependency provenance.
  • Update README.md and SKILL.md to direct users to the locked, integrity-verified installation process.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (19)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documented behavior includes authenticated access to the user's YouTube account and automatic targeting of the latest upload, but this is not transparently bounded in the top-level declaration. That mismatch is dangerous because users or orchestrators may assume a narrower, safer skill while the implementation can modify live channel content and make targeting decisions automatically.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 32)May include surrounding context.

md
- [ ] **Python 3** installed
- [ ] **Dependencies installed**: `pip install youtube-transcript-api google-generativeai google-auth-oauthlib google-api-python-client`
- [ ] **Gemini API Key** available to pass as an argument
- [ ] **`credentials.json`** placed in `scripts/` *(only required for `--post` — download from Google Cloud Console as an OAuth 2.0 Desktop App client)*

## Features

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 33)May include surrounding context.

md
- [ ] **Python 3** installed
- [ ] **Dependencies installed**: `pip install youtube-transcript-api google-generativeai google-auth-oauthlib google-api-python-client`
- [ ] **Gemini API Key** available to pass as an argument
- [ ] **`credentials.json`** placed in `scripts/` *(only required for `--post` — download from Google Cloud Console as an OAuth 2.0 Desktop App client)*

## Features

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
- [ ] **Python 3** installed
- [ ] **Dependencies installed**: `pip install youtube-transcript-api google-generativeai google-auth-oauthlib google-api-python-client`
- [ ] **Gemini API Key** available to pass as an argument
- [ ] **`credentials.json`** placed in `scripts/` *(only required for `--post` — download from Google Cloud Console as an OAuth 2.0 Desktop App client)*

## Features

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
- [ ] **Python 3** installed
- [ ] **Dependencies installed**: `pip install youtube-transcript-api google-generativeai google-auth-oauthlib google-api-python-client`
- [ ] **Gemini API Key** available to pass as an argument
- [ ] **`credentials.json`** placed in `scripts/` *(only required for `--post` — download from Google Cloud Console as an OAuth 2.0 Desktop App client)*

## Features

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
- [ ] **Python 3** installed
- [ ] **Dependencies installed**: `pip install youtube-transcript-api google-generativeai google-auth-oauthlib google-api-python-client`
- [ ] **Gemini API Key** available to pass as an argument
- [ ] **`credentials.json`** placed in `scripts/` *(only required for `--post` — download from Google Cloud Console as an OAuth 2.0 Desktop App client)*

## Features

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/youtube_desc_generator.py (reported line 30)May include surrounding context.

python
- [ ] **Python 3** installed
- [ ] **Dependencies installed**: `pip install youtube-transcript-api google-generativeai google-auth-oauthlib google-api-python-client`
- [ ] **Gemini API Key** available to pass as an argument
- [ ] **`credentials.json`** placed in `scripts/` *(only required for `--post` — download from Google Cloud Console as an OAuth 2.0 Desktop App client)*

## Features

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README promotes automatic appending of timestamps to YouTube descriptions but does not prominently warn that this modifies live channel content using retained OAuth credentials. In a skill that can operate via natural language, underemphasizing the consequences of write access makes accidental or unsafe use more likely.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README defines broad natural-language rules such as treating words like "post", "update", "upload", or references to a "latest video" as sufficient to trigger write operations against a live YouTube channel. In an agent setting, this can cause unintended or ambiguous user prompts to be translated into state-changing actions, increasing the risk of accidental modification of public video descriptions.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill clearly documents network-dependent behavior including transcript retrieval, Gemini API calls, and YouTube Data API updates, yet it declares no explicit tool scope or permissions. In an agent environment, this hides the real capability boundary and can cause the skill to be invoked without appropriate user awareness or policy gating.

Content

No source excerpt is available for this finding.

Whitespace Padding

Medium
Category
Prompt Injection
Confidence
70% confidence
Finding

Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Content

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

md
When the user speaks naturally, map their intent to the correct command using the table below. Always extract the YouTube URL or transcript text from their message and substitute it into the command.

| What the user says                                                                     | Command to run                                                                                      |
| -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| "Create timestamps for my latest video"                                                | `python scripts/youtube_desc_generator.py --latest "$GEMINI_API_KEY" --post`                          |
| "Generate timestamps for this video: https://youtu.be/abc123"                          | `python scripts/youtube_desc_generator.py --url "https://youtu.be/abc123" "$GEMINI_API_KEY"`        |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

A common request such as creating timestamps for the latest video is mapped directly to a command that posts changes automatically, without an upfront warning at the point of invocation. This increases the chance of silent or surprising account modifications when a user may only have intended content generation, not publication.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The natural-language decision rules treat broad words like 'post', 'update', 'upload', or even an implied request about the latest video as authorization to modify YouTube descriptions. This can easily turn an ambiguous user request into an unintended write action against live content, especially because transcript mode posts to the latest upload rather than an explicitly named target.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring describes the second mode as 'Transcript file' that reads a pre-made transcript, but the argument parser defines --transcript as TRANSCRIPT_TEXT and the implementation directly uses args.transcript as in-memory text. This is an active contradiction between the documented interface and the actual behavior, not merely omitted detail.

Content

No source excerpt is available for this finding.

Insecure deserialization: pickle.load()

Medium
Category
Dangerous Code Execution
Confidence
96% confidence
Finding

The script deserializes token.pickle with pickle.load(), which can execute arbitrary Python code if that file is replaced or tampered with. In a skill context that stores OAuth tokens beside the script, any attacker who can write to that path can turn a normal run into local code execution under the user's account.

Content

Scanner excerpt · scripts/youtube_desc_generator.py (reported line 39)May include surrounding context.

python
creds = None
    if os.path.exists(TOKEN_PICKLE):
        with open(TOKEN_PICKLE, 'rb') as token:
            creds = pickle.load(token)

    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The parser description says 'YouTube URL or transcript file,' yet the --transcript option is labeled TRANSCRIPT_TEXT and later assigned directly to formatted_transcript without file I/O. This mismatches the documented intent of file-based processing and could mislead users about what data the skill will consume.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Transcript content is sent to an external generative AI service without an explicit warning or consent step in the CLI, which can expose private, unpublished, or sensitive video content to a third party. In this skill, that risk is elevated because the tool is designed to process YouTube transcripts and may be used on creator-owned material not intended for external disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

When --post is used, the script directly updates the YouTube description with generated output and no confirmation, preview gate, or rollback protection. Because the content is AI-generated and target selection may resolve to the latest upload, an operator mistake or prompt-induced bad output can silently alter remote user-owned content.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The transcript fetch logic hard-codes ['en'], which restricts operation to English transcripts only. This is a language/locale constraint, and the file does not offer a user opt-in or configurable language selection.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.