Back to skill

Security audit

Codex Profiler

Security checks for vulnerabilities and agentic risk

Overview

The skill has a real Codex account-management purpose, but it handles credentials, auth-store changes, and gateway restarts through risky temporary files and background shell scripts.

Install only if you are comfortable giving this skill access to Codex/OpenAI OAuth profile data and allowing it to change OpenClaw auth state. Prefer the documented gateway-native commands, avoid unsafe-direct flags, use only trusted profile names, and clean up /tmp/openclaw token or staged-auth artifacts after use.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/codex_auth.py:518
Finding

Shell Command Injection Through Unsanitized Profile Identifiers

Content
View full analysis
str: return (profile_id or "unknown").replace(":", "_") ``` ```python if args.queue_apply: os.makedirs("/tmp/openclaw", exist_ok=True) safe_profile = safe_profile_slug(profile_id) payload_path = f"/tmp/openclaw/codex-auth-apply-{safe_profile}.json" script_path = f"/tmp/openclaw/codex-auth-apply-{safe_profile}.sh" log_path = f"/tmp/openclaw/codex-auth-apply-{safe_profile}.log" status_path = per_profile_status_path(profile_id) write_json_atomic(payload_path, {"profile": profile_id, "tokens": tokens}) py = shlex.quote(sys.executable or "python3") this_file = shlex.quote(os.path.abspath(__file__)) payload_q = shlex.quote(payload_path) auth_q = shlex.quote(args.auth_path) log_q = shlex.quote(log_path) allow_default_flag = " --allow-default" if (profile_id == "openai-codex:default" and args.allow_default) else "" script = f"""#!/usr/bin/env bash set -euo pipefail {{ echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] codex-auth apply start profile={profile_id}"; {py} {this_file} apply --payload {payload_q} --auth-path {auth_q}{allow_default_flag}; echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] codex-auth apply done profile={profile_id}"; }} >> {log_q} 2>&1 """ Path(script_path).write_text(script, encoding="utf-8") os.chmod(script_path, 0o700) launcher = "nohup" unit_name = f"codex-auth-apply-{safe_profile}-{int(time.time())}" try: sd = subprocess.run( ["systemd-run", "--user", "--unit", unit_name, "--collect", "/bin/bash", script_path], capture_output=True, text=True, timeout=15, ) if sd.returncode == 0: launcher = "systemd-run" else: subprocess ...[truncated 2791 chars]
Remediation
View remediation
str: if not PROFILE_RE.fullmatch(value): raise ValueError("Invalid profile identifier") return value ``` 2. Explicitly reject path separators, whitespace, control characters, shell metacharacters, backticks, dollar signs, and newline characters. 3. Do not generate executable shell scripts containing dynamic data. Implement the queued apply operation in Python and invoke subprocesses with fixed argument arrays. 4. If shell generation cannot immediately be removed, shell-quote every dynamic value with `shlex.quote()` and avoid placing dynamic values inside executable shell syntax. 5. Derive filenames and systemd unit names from a cryptographic random identifier rather than directly from a profile name. 6. Apply the same validation to profile identifiers loaded from `auth-profiles.json`, since that file may contain externally modified or previously malicious values. 7. Add regression tests using values containing `$(...)`, backticks, semicolons, quotes, newlines, spaces, `../`, and absolute paths. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/codex_auth.py:525
Finding

OAuth Access and Refresh Tokens Persist in Predictable Temporary Files

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/codex_auth.py:501
Finding

OAuth State Validation Is Bypassable When the Callback Omits State

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (23)

Tainted flow: 'req' from os.getenv (line 297, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/codex_usage.py (reported line 276)May include surrounding context.

python
"""
    req = urllib.request.Request(endpoint, method="HEAD", headers={"User-Agent": "CodexBar"})
    try:
        with urllib.request.urlopen(req, timeout=timeout_sec):
            return True
    except urllib.error.HTTPError as e:
        # Host/path reachable; endpoint answered with HTTP status.

Tainted flow: 'req' from os.getenv (line 297, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/codex_usage.py (reported line 299)May include surrounding context.

python
start = time.time()
        req = urllib.request.Request(endpoint, headers=headers)
        try:
            with urllib.request.urlopen(req, timeout=timeout_sec) as resp:
                body = resp.read().decode("utf-8", errors="replace")
                elapsed_ms = int((time.time() - start) * 1000)
                parse_error = False

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/codex_auth.py (reported line 444)May include surrounding context.

python
s_finish.add_argument("--auth-path", default=AUTH_PATH_DEFAULT)
    s_finish.add_argument("--queue-apply", action="store_true", default=True, help="Queue stop/write/start apply script in background (strict default)")
    s_finish.add_argument("--allow-default", action="store_true", help="Required to mutate/auth the default profile")
    s_finish.add_argument("--allow-unsafe-direct", action="store_true", help="Allow direct in-process writes without off-host stop/write/start (not recommended)")

    s_apply = sub.add_parser("apply")
    s_apply.add_argument("--payload", required=True)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/codex_auth.py (reported line 581)May include surrounding context.

python
s_finish.add_argument("--auth-path", default=AUTH_PATH_DEFAULT)
    s_finish.add_argument("--queue-apply", action="store_true", default=True, help="Queue stop/write/start apply script in background (strict default)")
    s_finish.add_argument("--allow-default", action="store_true", help="Required to mutate/auth the default profile")
    s_finish.add_argument("--allow-unsafe-direct", action="store_true", help="Allow direct in-process writes without off-host stop/write/start (not recommended)")

    s_apply = sub.add_parser("apply")
    s_apply.add_argument("--payload", required=True)

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The utility writes executable shell scripts and staged auth data under /tmp and then launches them asynchronously via systemd-run or nohup. In the context of a usage-checking script, this is excessive and risky because it expands the attack surface, leaves sensitive operational artifacts on disk, and enables background execution of auth-store mutation and process-control actions beyond the original invocation lifecycle.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

This script is presented as a Codex usage-checking utility, but it also supports detaching or hard-deleting auth profiles, stopping a gateway process, overwriting the auth store, and restarting the gateway. That is dangerous because it combines a read-oriented status tool with destructive credential-store mutation and service control, creating an unusually powerful and abusable capability if invoked by an agent or user in the wrong context.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The presence of an --allow-unsafe-direct flag explicitly enables bypassing the safer queued/off-host path and permits direct writes to the auth store. That is dangerous because it normalizes an unsafe mode for destructive credential-state mutation, increasing the chance of accidental or agent-driven misuse against sensitive authentication material.

Content

Scanner excerpt · scripts/codex_usage.py (reported line 697)May include surrounding context.

python
)
    ap.add_argument("--dry-run", action="store_true", help="Show delete result without writing auth file")
    ap.add_argument("--ack-gateway-restart", action="store_true", help="Required confirmation: mutation will stop gateway, write auth store, and restart gateway")
    ap.add_argument("--allow-unsafe-direct", action="store_true", help="Allow direct in-process auth write for delete mutation (not recommended)")
    ap.add_argument("--format", choices=["json", "text"], default="json", help="Output format for usage checks")
    args = ap.parse_args()

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 83)May include surrounding context.

openclaw models auth order get --provider openai-codex --agent

text

Never skip verification. If results mismatch expectation, do not hand-edit files; diagnose and re-apply via gateway-native commands.

## How to run
```bash

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/codex_auth.py (reported line 26)May include surrounding context.

python
TOKEN_URL = "https://auth.openai.com/oauth/token"
REDIRECT_URI = "http://localhost:1455/auth/callback"
SCOPE = "openid profile email offline_access"
JWT_CLAIM_PATH = "https://api.openai.com/auth"
OPENCLAW_CONFIG_PATH = str(Path.home() / ".openclaw" / "openclaw.json")
BACKUP_DIR = "/tmp/openclaw/safety-backups"
APPLY_STATUS_PATH = "/tmp/openclaw/codex-auth-apply-last.json"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The auth store persists access and refresh tokens, expiry, and account identifiers to disk without any encryption, permission hardening, or explicit user-facing warning in this path. If the auth file is readable by other local processes or included in backups, long-lived refresh tokens could be stolen and abused for account access.

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/codex_auth.py (reported line 290)May include surrounding context.

python
def run_cmd(cmd):
    return subprocess.run(cmd, capture_output=True, text=True)


def stop_gateway_processes():

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/codex_auth.py (reported line 295)May include surrounding context.

python
def stop_gateway_processes():
    # Avoid `openclaw gateway stop` because CLI config parsing may fail.
    subprocess.run(["pkill", "-TERM", "-f", "^openclaw-gateway$"], capture_output=True, text=True)
    time.sleep(3)
    subprocess.run(["pkill", "-KILL", "-f", "^openclaw-gateway$"], capture_output=True, text=True)
    time.sleep(1)

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/codex_auth.py (reported line 297)May include surrounding context.

python
# Avoid `openclaw gateway stop` because CLI config parsing may fail.
    subprocess.run(["pkill", "-TERM", "-f", "^openclaw-gateway$"], capture_output=True, text=True)
    time.sleep(3)
    subprocess.run(["pkill", "-KILL", "-f", "^openclaw-gateway$"], capture_output=True, text=True)
    time.sleep(1)

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/codex_auth.py (reported line 309)May include surrounding context.

python
# Prefer direct gateway binary when present.
    gw_bin = shutil.which("openclaw-gateway")
    if gw_bin:
        subprocess.Popen([gw_bin], stdout=lf, stderr=lf, stdin=subprocess.DEVNULL, start_new_session=True)
        return log_path

    # Fallback for installs where only the CLI is on PATH.

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/codex_auth.py (reported line 317)May include surrounding context.

python
if not oc_bin:
        raise FileNotFoundError("Neither 'openclaw-gateway' nor 'openclaw' found on PATH")

    subprocess.run([oc_bin, "gateway", "start"], stdout=lf, stderr=lf, stdin=subprocess.DEVNULL, check=False)
    return log_path

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The finish flow writes OAuth access and refresh tokens into a JSON payload under /tmp/openclaw before launching the apply step. Temporary files under /tmp can be exposed to other local users or recovered later if permissions are not explicitly restricted, and this code does not set secure file modes or provide clear disclosure to the user at the write point.

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/codex_auth.py (reported line 548)May include surrounding context.

python
launcher = "nohup"
            unit_name = f"codex-auth-apply-{safe_profile}-{int(time.time())}"
            try:
                sd = subprocess.run(
                    ["systemd-run", "--user", "--unit", unit_name, "--collect", "/bin/bash", script_path],
                    capture_output=True,
                    text=True,

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/codex_usage.py (reported line 83)May include surrounding context.

python
def launch_offhost_script(script_path, unit_name):
    try:
        sd = subprocess.run(
            ["systemd-run", "--user", "--unit", unit_name, "--collect", "/bin/bash", script_path],
            capture_output=True,
            text=True,

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/codex_auth.py (reported line 557)May include surrounding context.

python
except Exception:
        pass

    subprocess.Popen(["nohup", "bash", script_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)
    return "nohup", ""

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/codex_auth.py (reported line 559)May include surrounding context.

python
except Exception:
        pass

    subprocess.Popen(["nohup", "bash", script_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)
    return "nohup", ""

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/codex_usage.py (reported line 94)May include surrounding context.

python
except Exception:
        pass

    subprocess.Popen(["nohup", "bash", script_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)
    return "nohup", ""

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

The script deliberately restarts openclaw-gateway in the background with nohup, creating persistence of a service-control side effect after the invoking context exits. In an agent skill, that is risky because it allows the tool to alter long-lived system state and keep processes running independently of user review or containment boundaries.

Content

Scanner excerpt · scripts/codex_usage.py (reported line 131)May include surrounding context.

python
sleep 1

cp {staged_q} {auth_q}
nohup openclaw-gateway >/tmp/openclaw/openclaw-gateway-offhost-delete-start.log 2>&1 < /dev/null &
sleep 5

python3 - <<'PY'

Internal Network Request

Medium
Category
Server-Side Request Forgery
Confidence
70% confidence
Finding

Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.

Content

Scanner excerpt · scripts/codex_usage.py (reported line 148)May include surrounding context.

python
profiles = auth.get('profiles') or {{}}
status['present_after'] = [t for t in status['targets'] if t in profiles]
try:
  with urllib.request.urlopen('http://127.0.0.1:18789/health', timeout=4) as r:
    status['gateway_health'] = r.read().decode('utf-8', errors='replace')[:200]
except Exception as e:
  status['gateway_health'] = f'error:{{e}}'

Static analysis

No suspicious patterns detected.