Back to skill

Security audit

GPT Image 2 — Image Generation via Your ChatGPT Subscription

Security checks for vulnerabilities and agentic risk

Overview

This image-generation skill is mostly coherent, but it should be reviewed because it relies on saved Codex session logs and has weak isolation around what local session data may be read.

Install only if you are comfortable letting the skill use your logged-in Codex/ChatGPT session, persist the image request in Codex session history, and read newly created Codex rollout files under ~/.codex/sessions. Avoid running it alongside other Codex jobs that may create session rollouts, and do not use it for prompts or references that should not be retained locally in Codex logs.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gen.sh:61
Finding

Session Rollout Race Can Expose Unrelated Codex Conversations

Content
View full analysis
/dev/null | sort > "$before" || true ``` ```bash find "$SESSIONS_ROOT" -type f -name 'rollout-*.jsonl' -print 2>/dev/null | sort > "$after" || true # Collect ALL new session files. A single `codex exec` call can spawn more # than one session rollout (e.g. when the imagegen tool runs in a sub-turn), # so we must scan every new one rather than blindly picking the last. new_sessions_file="$(mktemp)" trap 'rm -f "$before" "$after" "$stdout_log" "$stderr_log" "$new_sessions_file"' EXIT comm -13 "$before" "$after" > "$new_sessions_file" || true if [[ ! -s "$new_sessions_file" ]]; then echo "No new session rollout file under $SESSIONS_ROOT" >&2 tail -n 40 "$stderr_log" >&2 || true exit 6 fi ``` From `scripts/extract_image.py`: ```python def find_best_image_blob(session_paths: list[pathlib.Path]) -> tuple[str, str] | None: """Return the largest (base64, ext) image payload found across given files.""" best: tuple[str, str, int] | None = None for session_path in session_paths: try: text = session_path.read_text(errors="replace") except OSError: continue for line in text.splitlines(): try: obj = json.loads(line) except ValueError: continue flat = json.dumps(obj) for match in BASE64_BLOB_PATTERN.finditer(flat): blob = match.group(1) for magic, ext in IMAGE_MAGIC_PREFIXES.items(): if blob.startswith(magic): if best is None or len(blob) > best[2]: best = (blob, ext, len(blob)) ...[truncated 2314 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gen.sh:70
Finding

Untrusted Prompt Is Passed to a General-Purpose Agent with Broad Read Access

Content
View full analysis
&2; exit 4; } args+=(-i "$img") done fi instruction="Use the imagegen tool to generate the image for the following request." if [[ ${#REF_IMAGES[@]} -gt 0 ]]; then instruction+=" Use the attached image(s) as visual reference / input for image-to-image." fi instruction+=$'\nRequirements: generate the image directly, return only the image, no explanation.\n\nRequest:\n'"$PROMPT" # `-i` is a variadic flag (...), so passing the prompt as the trailing # positional would be consumed as another image file. Feed the prompt via # stdin instead (codex exec reads from stdin when no prompt positional is # given). TO="" if command -v timeout >/dev/null 2>&1; then TO="timeout" elif command -v gtimeout >/dev/null 2>&1; then TO="gtimeout" fi set +e if [[ -n "$TO" ]]; then printf '%s' "$instruction" | "$TO" "$TIMEOUT_SEC" codex "${args[@]}" >"$stdout_log" 2>"$stderr_log" else printf '%s' "$instruction" | codex "${args[@]}" >"$stdout_log" 2>"$stderr_log" fi ``` ### Technical Analysis The caller-controlled prompt is concatenated directly into instructions supplied to a nested, general-purpose Codex agent. Although the process uses `--sandbox read-only`, this setting primarily limits writes; it does not confine reads to the supplied reference images or a dedicated workspace. The trusted instruction and untrusted request are passed through the same natural-language channel. A malicious request can therefore attempt to override the image- ...[truncated 1629 chars]
Remediation
View remediation
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (3)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description claims a full image-generation and editing capability through GPT Image 2 inside Claude Code. However, this code chunk does not perform any generation, editing, or model interaction at all. Its sole purpose is post-processing: reading session files, locating embedded base64 image data, and exporting that data to an output image file. While this could be a supporting helper within a larger image-generation skill, the supplied chunk by itself materially differs from the declared primary purpose and exposes a distinct capability—session-log image extraction—that is not described.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill explicitly describes file reads from ~/.codex/sessions and file writes to an arbitrary --out path, but it declares no tool scope or allowed-tools restrictions. That creates an avoidable over-privilege gap: an agent invoking this skill may gain broader read/write capability than users or reviewers expect, increasing the chance of unintended access to local files or misuse of output paths.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
95% confidence
Finding

The script deliberately disables ephemeral execution so Codex session rollouts are persisted under ~/.codex/sessions, then reads those files back to extract base64 image data. Those persisted session files can contain the user's prompts, reference-image metadata, generated content, and potentially other session context, creating unnecessary local retention of sensitive data beyond the requested output image.

Content

Scanner excerpt · scripts/gen.sh (reported line 6)May include surrounding context.

sh
# ChatGPT subscription session. Supports text-to-image and image-to-image.
#
# Implementation note: on codex-cli 0.111.0 the `imagegen` tool does NOT
# write a PNG file to disk. The generated image is embedded as base64 inside
# the session rollout jsonl under ~/.codex/sessions/YYYY/MM/DD/. This script
# captures the new session file created by the run and decodes the image
# out of it. Flags: `--enable image_generation` turns the under-development