Back to skill

Security audit

Auto Midjourney

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent Midjourney automation purpose, but it gives broad authenticated browser and session-cookie access with weak destination controls that users should review before installing.

Install only if you are comfortable giving the skill access to your logged-in Midjourney session. Use a dedicated browser profile, keep the .env file private, avoid custom endpoint URLs unless you fully trust them, do not run it on shared or untrusted machines, and review output before sharing because diagnostics and logs may include account or prompt data.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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/mj_alpha.py:117
Finding

Authenticated Session Cookie Can Be Sent to Arbitrary Configured Endpoints

Content
View full analysis
dict[str, str]: headers = { "accept": "*/*", "content-type": "application/json", "cookie": config.cookie, "origin": config.origin, "referer": config.origin.rstrip("/") + config.referer_path, "user-agent": config.user_agent, "x-csrf-protection": config.csrf_protection, "x-mj-traceparent": build_traceparent(), } if config.metrics_token: headers["x-metrics-token"] = config.metrics_token headers.update(config.extra_headers) return headers ``` ```python def poll_job( config: MJConfig, job_id: str, *, attempts: int = 60, interval_seconds: float | None = None, once: bool = False, ) -> dict[str, Any]: status_url = resolve_status_url(config.status_url_template, job_id) if not status_url: raise RuntimeError("MJ_STATUS_URL_TEMPLATE is not configured") interval = config.poll_interval_seconds if interval_seconds is None else interval_seconds headers = build_headers(config) history: list[dict[str, Any]] = [] for attempt in range(1, max(1, attempts) + 1): data = get_json(status_url, headers=headers, timeout_seconds=config.timeout_s ...[truncated 2089 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mj_alpha.py:568
Finding

Unvalidated Image Downloads Forward the Full Session Cookie

Content
View full analysis
list[str]: urls: list[str] = [] walk_and_collect( data, lambda value: isinstance(value, str) and IMAGE_URL_RE.match(value) is not None, urls, ) return dedupe(urls) ``` ```python def fetch_binary( url: str, headers: dict[str, str], timeout_seconds: float, ) -> tuple[bytes, str | None]: request = urllib.request.Request(url=url, headers=headers, method="GET") try: with urllib.request.urlopen(request, timeout=timeout_seconds) as response: return response.read(), response.headers.get_content_type() except urllib.error.HTTPError as exc: body = exc.read().decode("utf-8", errors="replace") raise RuntimeError( f"HTTP {exc.code} for {request.full_url}: {body}" ) from exc except (urllib.error.URLError, ssl.SSLError) as exc: if _is_tls_protocol_error(exc): return _curl_request_bytes(request, timeout_seconds), None raise RuntimeError(f"Request failed for {request.full_url}: {exc}") from exc ``` ```python data, content_type = fetch_binary( image_url, headers=build_headers(config), timeout_seconds=config.timeout_seconds, ) extension = infer_extension_from_url_or_type(image_url, content_type) output_path = path / f"{safe_slug(filename_stem)}{extension}" output_path.write_bytes(data) ``` ### Technical Analysis Result extraction accepts any HTTPS URL ending in a supported image extension. It does not require the URL to use an approved Midjourney CDN hostname. The original-format download path then calls `fetch_binary()` with `build_headers(config)`. Those headers include the full authenticated Midjourney cookie. A malicious result document c ...[truncated 1352 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mj_browser.py:159
Finding

Full Session Cookie Is Exposed in Child-Process Command-Line Arguments

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/mj_doctor.py:36
Finding

Diagnostic Command Discloses Personal Identity Claims

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/mj_browser.py:20
Finding

Predictable Chrome DevTools Endpoint Exposes an Authenticated Browser Control Surface

Content
View full analysis
list[str]: args = [ f"--remote-debugging-port={CDP_PORT}", f"--user-data-dir={CDP_PROFILE_DIR}", "--new-window", ] if CHROME_PROXY: args.append(f"--proxy-server={CHROME_PROXY}") args.append(url) return args ``` ```python def ensure_debug_chrome(url: str = MIDJOURNEY_TAB_URL) -> None: if _check_cdp_ready(): return Path(CDP_PROFILE_DIR).mkdir(parents=True, exist_ok=True) _launch_debug_chrome(url) deadline = time.time() + 15 while time.time() < deadline: if _check_cdp_ready(): return time.sleep(0.5) raise RuntimeError("Chrome DevTools endpoint did not become ready") ``` ### Technical Analysis The Skill launches Chrome with remote debugging enabled on the predictable default port `9222` and stores its state in a persistent, predictable profile directory. The same browser is then populated with the user's authenticated Midjourney cookies. Chrome DevTools Protocol access provides extensive control over browser targets, including JavaScript execution, page inspection, network observation, cookie manipulation, and navigation. Any untrusted local process that can reach the endpoint while it is active may control the authenticated browser session. The code checks the endpoint using `127.0.0.1`, but it does not establish authentication for CDP, allocate an unpredictable endpoint, enforce profile cleanup, or terminate the browser after an operation. ### Attack Path 1. The user invokes browser transport. 2. The Skill la ...[truncated 1016 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (69)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The documented behavior does not accurately bound what the skill actually does, particularly around filesystem scanning, writing, optional deletion, image conversion, and manifest/URL rebuilding workflows. This is dangerous because users and reviewers may authorize the skill for authenticated Midjourney automation while overlooking broader local-file operations that can affect privacy, integrity, and reviewability.

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 105)May include surrounding context.

md
Never write real cookies or tokens into `SKILL.md`, reference files, git-tracked scripts, or user-facing summaries.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/batch_generate.py (reported line 92)May include surrounding context.

python
if not line or line.startswith("#"):
            continue
        prompts.append(line)
    return prompts


def resolve_preset_suffix(presets_file: str, preset_name: str | None) -> str | None:

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script accepts a caller-controlled --request-url and then executes fetch() inside the authenticated browser context with credentials included, without enforcing any allowlist for Midjourney-owned origins. That creates a general authenticated request primitive through the user's live browser session, enabling misuse for unintended endpoints, internal APIs reachable from the browser, or other web actions beyond the stated Midjourney automation purpose.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The bridge accepts caller-supplied JavaScript and executes it via eval() inside page.evaluate() in an authenticated browser session connected over CDP. That gives any upstream caller the ability to run arbitrary code in the Midjourney web context, read page state, trigger privileged actions, and potentially access authenticated data far beyond the stated automation need.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/batch_generate.py (reported line 54)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/get_user_state.py (reported line 19)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/list_recent_jobs.py (reported line 28)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/mj_alpha.py (reported line 54)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/mj_doctor.py (reported line 28)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/poll_job.py (reported line 19)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/run_imagine.py (reported line 46)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/submit_job.py (reported line 19)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/batch_generate.py (reported line 54)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/get_user_state.py (reported line 19)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/list_recent_jobs.py (reported line 28)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/mj_doctor.py (reported line 28)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/poll_job.py (reported line 19)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/run_imagine.py (reported line 46)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/submit_job.py (reported line 19)May include surrounding context.

python
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="Submit one Midjourney Alpha imagine job.")
    parser.add_argument("prompt", help="Full prompt to submit")
    parser.add_argument("--dotenv", default=".env", help="Path to .env file")
    parser.add_argument("--channel-id", help="Override MJ_CHANNEL_ID")
    parser.add_argument("--mode", help="Override MJ_MODE, for example fast")
    parser.add_argument("--private", action="store_true", help="Submit as private/stealth")

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill exposes sensitive capabilities including environment-variable access, filesystem read/write, shell execution, and network use, but does not declare any explicit tool scope or permission boundaries. In this context, the skill is specifically designed to handle authenticated Midjourney cookies and browser-backed automation, so the absence of scoped permissions increases the risk of overbroad access, credential misuse, and unintended side effects if the skill is invoked or extended unsafely.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger rules are written entirely as Chinese phrases and the skill repeatedly instructs proactive use based on those phrases, but the document does not offer an opt-in or alternative language choice. This creates a natural-language locale constraint that is not documented as region-specific or optional.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

All user-facing prompt examples in this file are written in Chinese, with no indication that the skill supports other languages or that Chinese is optional. This can constitute a language/locale policy issue if the skill behavior or evaluation setup implicitly requires a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code unlinks the original source file after conversion when --delete-original is set, but there is no confirmation prompt, warning print, or nearby comment/docstring disclosing that deletion is happening at execution time. Because this is a destructive file operation, the file itself lacks user-facing disclosure beyond the argument help text.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
77% confidence
Finding

The script performs authenticated network requests to fetch user state, including use of CSRF-related headers and config-derived request parameters, but provides no runtime notice, warning comment, or other disclosure that account-related data will be transmitted and retrieved. This is a safety-relevant network operation and the file itself does not visibly warn the user about its privacy implications.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/mj_playwright_bridge.mjs:140