Back to skill

Security audit

Skill X Post Ai Image

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it handles account credentials too broadly when spawning helper commands.

Review before installing. Only run this with X/Twitter credentials you are comfortable using for public posting, avoid sensitive text or image prompts, and prefer a version that passes only necessary environment variables to uv and xurl and constrains the image-generator path.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (1)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/post_with_image.py:25
Finding

Excessive Credential Propagation to Child Processes

Content
View full analysis
str: result = subprocess.run( ["uv", "run", NANO_BANANA_SCRIPT, "--prompt", prompt, "--filename", out_path, "--resolution", "1K"], capture_output=True, text=True, env={**os.environ, "GEMINI_API_KEY": os.environ.get("GEMINI_API_KEY", "")} ) ``` ```python def post_tweet(text: str, media_id: str = None): cmd = ["xurl", "post", text] if media_id: cmd += ["--media-id", media_id] result = subprocess.run(cmd, capture_output=True, text=True) print(result.stdout) if result.returncode != 0: raise RuntimeError(result.stderr) ``` ### Technical Analysis The image-generation subprocess is explicitly given a copy of the entire parent environment through `env={**os.environ, ...}`. The parent environment contains the Twitter OAuth credentials read by this script: - `X_CONSUMER_KEY` - `X_CONSUMER_SECRET` - `X_ACCESS_TOKEN` - `X_ACCESS_TOKEN_SECRET` The image generator only requires the Gemini credential, but it also receives all Twitter credentials and any other secrets present in the process environment. In addition, `NANO_BANANA_SCRIPT` is configurable through an environment variable. If an attacker can influence that variable, the selected script can directly inspect its inherited environment. The `xurl` subprocess does not provide an explicit environment, so Python gives it the complete inherited environment by default. It can therefore access `GEMINI_API_KEY` and unrelated sensitive variables even though they are unnecessary for ...[truncated 1856 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (10)

Direct flow: os.environ.get (credential/environment) → subprocess.run (code execution)

High
Category
Data Flow
Confidence
97% confidence
Finding

The subprocess is launched with env={**os.environ, ...}, which forwards the entire parent environment to an external script. In a skill context, that can expose unrelated secrets such as X OAuth tokens or other API keys to the invoked code, making this a real secret-leak and privilege-extension risk.

Content

Scanner excerpt · scripts/post_with_image.py (reported line 20)May include surrounding context.

python
)

def generate_image(prompt: str, out_path: str) -> str:
    result = subprocess.run(
        ["uv", "run", NANO_BANANA_SCRIPT, "--prompt", prompt, "--filename", out_path, "--resolution", "1K"],
        capture_output=True, text=True,
        env={**os.environ, "GEMINI_API_KEY": os.environ.get("GEMINI_API_KEY", "")}

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
99% confidence
Finding

The code explicitly clones the full process environment into a child process, which can leak all available secrets to external code. In this skill, that likely includes X OAuth credentials and any other agent/runtime secrets, making the image-generation helper a privileged secret sink if compromised or replaced.

Content

Scanner excerpt · scripts/post_with_image.py (reported line 23)May include surrounding context.

python
result = subprocess.run(
        ["uv", "run", NANO_BANANA_SCRIPT, "--prompt", prompt, "--filename", out_path, "--resolution", "1K"],
        capture_output=True, text=True,
        env={**os.environ, "GEMINI_API_KEY": os.environ.get("GEMINI_API_KEY", "")}
    )
    if result.returncode != 0:
        raise RuntimeError(f"Image gen failed: {result.stderr}")

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill declares capabilities that rely on environment variables and shell-executed tools, but it does not define an explicit tool scope such as permissions or allowed-tools. In an agent setting, this can lead to over-broad execution authority, making it easier for the skill to access secrets or invoke commands beyond what is necessary for posting to X and generating media.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill posts content publicly to X/Twitter and sends prompts or generated media to external services, but it does not clearly warn users about that disclosure. This is dangerous because users may provide sensitive, private, or regulated content without realizing it will be transmitted to third parties and potentially published publicly.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest says this skill generates an AI image via Gemini and posts it to X, but the implementation delegates image generation to a separate script using subprocess.run and a configurable path from NANO_BANANA_SCRIPT. Spawning an external process is a materially broader capability than directly calling a Gemini API and allows execution of whatever script path is supplied, which is not justified by the stated purpose alone.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
94% confidence
Finding

The script executes an external program using subprocess and allows the target script path to be overridden via the NANO_BANANA_SCRIPT environment variable. While shell injection is avoided by passing an argument list, this still permits execution of attacker-controlled code if the environment is influenced, and the child process inherits the full environment including sensitive tokens.

Content

Scanner excerpt · scripts/post_with_image.py (reported line 20)May include surrounding context.

python
)

def generate_image(prompt: str, out_path: str) -> str:
    result = subprocess.run(
        ["uv", "run", NANO_BANANA_SCRIPT, "--prompt", prompt, "--filename", out_path, "--resolution", "1K"],
        capture_output=True, text=True,
        env={**os.environ, "GEMINI_API_KEY": os.environ.get("GEMINI_API_KEY", "")}

Tainted flow: 'NANO_BANANA_SCRIPT' from os.environ.get (line 14, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Confidence
96% confidence
Finding

NANO_BANANA_SCRIPT is sourced from an environment variable and then executed by uv run. If an attacker can control the environment or deployment configuration, they can redirect execution to arbitrary local code that receives inherited secrets and can perform unintended actions.

Content

Scanner excerpt · scripts/post_with_image.py (reported line 20)May include surrounding context.

python
)

def generate_image(prompt: str, out_path: str) -> str:
    result = subprocess.run(
        ["uv", "run", NANO_BANANA_SCRIPT, "--prompt", prompt, "--filename", out_path, "--resolution", "1K"],
        capture_output=True, text=True,
        env={**os.environ, "GEMINI_API_KEY": os.environ.get("GEMINI_API_KEY", "")}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code performs outbound posting operations to Twitter/X, including media upload and tweet publication, but only prints progress messages like "Uploading..." and "Posting tweet..." rather than warning the user that content will be transmitted to a third-party service. The module docstring states the purpose, but it does not disclose the concrete network side effects or provide any confirmation before publication.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/post_with_image.py (reported line 51)May include surrounding context.

python
cmd = ["xurl", "post", text]
    if media_id:
        cmd += ["--media-id", media_id]
    result = subprocess.run(cmd, capture_output=True, text=True)
    print(result.stdout)
    if result.returncode != 0:
        raise RuntimeError(result.stderr)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The script accesses X API credentials from environment variables at startup, but there is no user-facing notice that sensitive tokens are required and will be used for authenticated posting. Under the stated criteria, access to sensitive environment variables should have some disclosure via comments, docstring, or user-visible messaging.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.