Back to skill

Security audit

Codex Thread Repair

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a disclosed local Codex repair tool, but it contains a real launcher command-injection flaw and uses an unpinned third-party install path.

Install from ClawHub or a pinned, reviewed commit rather than the unpinned `npx -y` command. Do not run a generated `.command` launcher unless you have inspected the resolved thread ID or the publisher has fixed the launcher escaping/validation issue; this tool can modify your local Codex conversation files and should be used only for the specific supported repair case.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/thread_repair.py:652
Finding
Shell Command Injection Through an Unvalidated Thread ID<![CDATA[ ## Vulnerability Details **File Location**: `scripts/thread_repair.py:652-673` **Vulnerability Type**: Shell command injection **Risk Level**: High ### Vulnerable Code ```python thread_id = result["thread"]["id"] output_path = Path(args.output).expanduser() if args.output else ( Path.home() / "Desktop" / f"repair-codex-thread-{thread_id[:8]}.command" ) output_path = output_path.resolve() if not output_path.parent.is_dir(): raise RepairError(f"Launcher parent directory does not exist: {output_path.parent}") if output_path.exists(): raise RepairError( f"Refusing to overwrite existing launcher: {output_path}; choose another --output path" ) log_path = output_path.with_suffix(".log") script_path = Path(__file__).resolve() command = " ".join( [ "/usr/bin/env", "python3", shlex.quote(str(script_path)), "--codex-home", shlex.quote(str(args.codex_home)), "apply", shlex.quote(thread_id), "--reopen", ] ) launcher = f"""#!/bin/bash set -uo pipefail export PATH=\"/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin\" readonly REPAIR_LOG={shlex.quote(str(log_path))} printf '\\n=== Codex thread repair: {thread_id} ===\\n' printf 'Press Cmd+Q in Codex before continuing.\\n' {command} 2>&1 | tee -a \"$REPAIR_LOG\" ``` ### Technical Analysis The thread ID is loaded from the local Codex SQLite database and inserted directly into a single-quoted shell command in the generated `.command` launcher: ```bash printf '\n=== Codex thread repair: {thread_id} ===\n' ``` Although the thread ID is safely quoted with `shlex.quote()` when used as an argument to the Python repair command, it is not escaped in the preceding `printf` statement. A thread ID containing a single quote followed by shell syntax can terminate the quoted string and introduce arbitrary commands. The project defines `SAFE_THREAD_ID_PATTERN`, but `command_prepare()` does not apply that validation before creating th ...[truncated 1674 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate the thread ID immediately after retrieving it and before using it in any filename, shell source, log output, or command: ```python thread_id = result["thread"]["id"] if ( not isinstance(thread_id, str) or not SAFE_THREAD_ID_PATTERN.fullmatch(thread_id) or thread_id in {".", ".."} ): raise RepairError(f"Unsafe thread ID: {thread_id!r}") ``` 2. Do not interpolate untrusted values into shell program text. Quote the value as a separate `printf` argument: ```python quoted_thread_id = shlex.quote(thread_id) launcher = f"""#!/bin/bash set -uo pipefail printf '\\n=== Codex thread repair: %s ===\\n' {quoted_thread_id} """ ``` 3. Prefer generating a launcher that contains only fixed shell syntax and passes all variable data as safely quoted positional arguments. 4. Add regression tests using IDs containing single quotes, command substitutions, semicolons, newlines, spaces, slashes, and redirection operators. Confirm that unsafe IDs are rejected before the launcher is written. 5. Apply the same validation at the database trust boundary in `resolve_thread()` so every downstream command receives a validated identifier. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:15
Finding
Unpinned Third-Party Package Execution in Installation Instructions<![CDATA[ ## Vulnerability Details **File Location**: `README.md:15` **Vulnerability Type**: Unpinned dependency and supply-chain execution risk **Risk Level**: Medium ### Vulnerable Code ```bash npx -y skills add Songhonglei/better-agent-skills -s codex-thread-repair ``` ### Technical Analysis The documented installation command uses `npx -y` to retrieve and execute the currently resolved version of the npm package named `skills`. No package version, lockfile, package integrity value, or verified artifact digest is specified. The referenced GitHub repository is also not pinned to a release tag or immutable commit. Consequently, the effective installation logic and installed Skill content can change after this audited project version was reviewed. Because `npx` executes package-provided code, compromise of the npm package, an unsafe future release, changes in package resolution, or compromise of the mutable upstream repository could introduce code execution during installation. This finding concerns the documented installation path. The audited repair script itself uses only the Python standard library and does not retrieve or execute a remote payload during normal repair operations. ### Attack Path 1. The npm package resolved as `skills`, or its publication account, is compromised or publishes a malicious update. 2. Alternatively, the mutable repository content referenced by the installer is changed or compromised. 3. A user follows the README and runs the unpinned `npx -y` command. 4. `npx` downloads the currently available package version without interactive package approval. 5. Package lifecycle or CLI code executes with the invoking user's privileges. 6. Malicious installer behavior can alter files or install a modified Skill before the user reviews its contents. ### Impact Assessment A compromised installer can execute code with the privileges of the user running the command. It may modify user-owned files, install altered Skill instructions o ...[truncated 311 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the npm package to a reviewed, explicit version: ```bash npx -y skills@<reviewed-version> add Songhonglei/better-agent-skills@<immutable-commit> -s codex-thread-repair ``` 2. Pin repository content to an immutable commit hash rather than a mutable branch. 3. Publish and document SHA-256 checksums or signed release artifacts so users can verify downloaded content before installation. 4. Prefer a manual installation path from a specific signed release when reproducibility and auditability are required. 5. Document the exact expected npm package owner, package version, repository commit, and installed file hashes. 6. Consider removing automatic `-y` approval from security-sensitive installation guidance so users can inspect the package and resolved version before execution. ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill invokes Python scripts that read environment variables, execute shell commands, and perform direct file reads/writes against local Codex state, including mutation and rollback operations. Even though these capabilities are central to the repair workflow, the absence of an explicit permissions declaration weakens user awareness and policy enforcement, increasing the chance that a powerful local-state-modifying skill is run with insufficient scrutiny.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
tests/test_thread_repair.py:22