T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/gen.sh:61
- Finding
- Session Rollout Race Can Expose Unrelated Codex Conversations<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gen.sh:61-62, 104-116`; `scripts/extract_image.py:27-47, 99-103` **Vulnerability Type**: Race condition and insufficient session-file isolation **Risk Level**: Medium ### Vulnerable Code From `scripts/gen.sh`: ```bash find "$SESSIONS_ROOT" -type f -name 'rollout-*.jsonl' -print 2>/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
- <![CDATA[ ## Remediation Suggestions 1. Run Codex with an isolated temporary session home or dedicated session directory so the invocation cannot see unrelated rollouts. 2. Prefer obtaining the exact session identifier or rollout path directly from the spawned Codex process rather than inferring ownership through directory differences. 3. Validate that every selected rollout belongs to the child process using a cryptographically random invocation identifier or trusted session metadata. 4. Add an exclusive filesystem lock around snapshot creation, Codex execution, and extraction if shared global session storage is unavoidable. 5. Reject rollout paths outside the expected canonical session root and verify file ownership before reading. 6. Update the documentation so its isolation and concurrency claims accurately reflect the implemented guarantees. ]]>
