Back to skill

Security audit

cpa-codex-auth-sweep-cliproxy

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do its stated auth-scanning job, but it handles powerful credentials with endpoint controls that are too easy to broaden and it can delete auth files in bulk.

Install only if you fully trust the CLI Proxy server, the operator environment, and the exact command invocation. Keep the probe host at the default chatgpt.com target, avoid overriding the allowed host list, avoid --allow-unsafe-probe-host and --insecure, and do not use --delete-401 --yes unless you have reviewed the generated deletion targets and can recover deleted auth files.

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/cliproxy_scanner.py:159
Finding

Caller-Controlled Allowlist Permits Exfiltration of Codex Bearer Tokens

Content
View full analysis
None: parsed = urlparse(probe_url) if parsed.scheme != "https": raise SystemExit("Security check failed: --probe-url must use https") host = (parsed.hostname or "").lower() allowed = _normalize_hosts_csv(allowed_hosts_csv) if not host: raise SystemExit("Security check failed: --probe-url host is empty") if host not in allowed: if unsafe_allow: return raise SystemExit( f"Security check failed: probe host '{host}' not in allowlist {sorted(allowed)}. " "Use --allow-unsafe-probe-host only if you fully trust this host." ) ``` ```python p.add_argument("--allowed-probe-hosts", default=DEFAULT_ALLOWED_PROBE_HOSTS, help="Comma-separated allowlist for probe host, default: chatgpt.com") p.add_argument("--allow-unsafe-probe-host", action="store_true", help="Allow probe host outside allowlist (DANGEROUS)") ``` ### Technical Analysis The management API replaces the `$TOKEN$` placeholder in the probe Authorization header with the real Codex bearer token and sends it to `probe_url`. This network transmission is necessary for the declare ...[truncated 2051 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cliproxy_scanner.py:108
Finding

Management Key Can Be Sent to an Untrusted or Plaintext Management Endpoint

Content
View full analysis
list[AuthEntry]: url = base_url.rstrip("/") + endpoint code, resp = _json_request( url, "GET", {"Authorization": f"Bearer {key}", "Accept": "application/json"}, None, timeout=30, insecure=insecure, ) ``` The same unvalidated base URL is used for destructive requests: ```python def _delete_auth_file(base_url: str, key: str, endpoint: str, name: str, insecure: bool) -> bool: url = f"{base_url.rstrip('/')}{endpoint}?name={quote(name, safe='')}" code, _ = _json_request( url, "DELETE", {"Authorization": f"Bearer {key}", "Accept": "application/json"}, None, timeout=30, insecure=insecure, ) return code < 400 ``` The input is only checked for presence: ```python if not args.base_url or not args.management_key: raise SystemExit("Missing required params: --base-url and --management-key") if args.workers < 1 or args.probe_workers < 1 or args.delete_workers < 1: raise SystemExit("--workers/--probe-workers/--delete-workers must be >= 1") if args.max_active_probes < 0: raise SystemExit("--max-active-probes must be >= 0") if args.progress_every < 1: raise SystemExit("--progress-every must be >= 1") if args.insecure and not args.allow_insecure_tls: raise SystemExit("Security check failed: --insecure requires explicit --allow-insecure-tls") _assert_probe_url_safe(args.probe_url, args.allowed_probe_hosts, args.allow_unsafe_probe_host) ``` ### Technical Analysis `base_url` determines where the primary CLI Proxy management key is sent. The code verifies only that this value is none ...[truncated 2062 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/cliproxy_scanner.py:94
Finding

Free-Form Status Messages Can Trigger Deletion Without a Current 401 Probe

Content
View full analysis
str: s = (auth.status_message or "") sl = s.lower() for kw in INVALID_TOKEN_KEYWORDS: if kw.lower() in sl: return f"status_message:{kw}" return "" ``` ```python # Stage 1: static quick match from status_message static_invalid: list[CheckResult] = [] active_candidates: list[AuthEntry] = [] for a in auths: reason = _match_static_reason(a) if reason: static_invalid.append(CheckResult(a.name, a.auth_index, None, True, False, "", a.status_message[:220], reason)) else: active_candidates.append(a) ``` ```python to_delete = [r.name for r in results if r.unauthorized_401] deleted = 0 if args.delete_401 and args.yes and to_delete: with concurrent.futures.ThreadPoolExecutor(max_workers=args.delete_workers) as ex: futs = [ex.submit(_delete_auth_file, args.base_url, args.management_key, args.auth_delete_endpoint, name, args.insecure) for name in to_delete] for f in concurrent.futures.as_completed(futs): if f.result(): deleted += 1 ``` ### Technical Analysis The scanner treats a case-insensitive substring match in the management server's free-form `status_message` as equivalent to a confirmed unauthorized response. It sets `unauthorized_401=True` even though `status_code` is `None`, and it excludes the credential from active probing. If deletion is enabled, every result with `una ...[truncated 1623 chars]
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
65% 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 · README.md (reported line 23)May include surrounding context.

md
- 仅允许 `https` probe URL
- 默认仅允许 host=`chatgpt.com`
- 非白名单 host 需显式 `--allow-unsafe-probe-host`(高风险)
- `--insecure` 需要二次确认 `--allow-insecure-tls`(高风险)

### 凭据声明

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
65% 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 · README.md (reported line 81)May include surrounding context.

md
- 仅允许 `https` probe URL
- 默认仅允许 host=`chatgpt.com`
- 非白名单 host 需显式 `--allow-unsafe-probe-host`(高风险)
- `--insecure` 需要二次确认 `--allow-insecure-tls`(高风险)

### 凭据声明

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
94% confidence
Finding

The skill explicitly supports an override flag (--allow-unsafe-probe-host) that permits sending Authorization: Bearer $TOKEN$ to a non-whitelisted probe-url. Even though the text warns and requires user confirmation, this creates a built-in path for credential exfiltration or SSRF-like abuse if a user is tricked, the confirmation is socially engineered, or the agent misapplies the option.

Content

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

md
1. 默认仅允许 `https://chatgpt.com/...` 作为探测目标。
2. 扫描前必须向用户确认 `probe-url`(若用户改过)。
3. 若要使用非白名单主机,必须得到用户明确授权,并显式传 `--allow-unsafe-probe-host`。
4. 禁止默认使用 `--insecure`;仅在内网排障且用户明确授权时,才可同时传 `--insecure --allow-insecure-tls`。

## 执行入口

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
89% confidence
Finding

The code explicitly allows bypassing the probe-host allowlist via --allow-unsafe-probe-host, enabling the management API to replay stored auth material against arbitrary HTTPS hosts. In this skill's context, which is built to sweep many Codex auth entries at high concurrency, that override materially increases SSRF-style abuse and credential exposure risk if an operator or upstream agent is tricked into using an attacker-controlled host.

Content

Scanner excerpt · scripts/cliproxy_scanner.py (reported line 223)May include surrounding context.

python
return
        raise SystemExit(
            f"Security check failed: probe host '{host}' not in allowlist {sorted(allowed)}. "
            "Use --allow-unsafe-probe-host only if you fully trust this host."
        )

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
88% confidence
Finding

Exposing --allow-unsafe-probe-host as a user-facing parameter makes it easy for callers to disable the primary destination safety control. Since the tool can invoke the management api-call endpoint using many stored auth entries, this parameter can be abused to direct authenticated outbound requests to untrusted infrastructure at scale.

Content

Scanner excerpt · scripts/cliproxy_scanner.py (reported line 242)May include surrounding context.

python
p.add_argument("--auth-delete-endpoint", default=DEFAULT_AUTH_DELETE_ENDPOINT)
    p.add_argument("--probe-url", default=DEFAULT_PROBE_URL)
    p.add_argument("--allowed-probe-hosts", default=DEFAULT_ALLOWED_PROBE_HOSTS, help="Comma-separated allowlist for probe host, default: chatgpt.com")
    p.add_argument("--allow-unsafe-probe-host", action="store_true", help="Allow probe host outside allowlist (DANGEROUS)")
    p.add_argument("--workers", type=int, default=DEFAULT_WORKERS)
    p.add_argument("--probe-workers", type=int, default=DEFAULT_PROBE_WORKERS)
    p.add_argument("--delete-workers", type=int, default=DEFAULT_DELETE_WORKERS)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill performs sensitive network operations and uses environment-provided secrets (management_key, base URLs, probe targets) but declares no explicit tool/permission scope. That increases the chance the agent can access network and secret-bearing inputs without clear least-privilege boundaries or policy enforcement, which is especially risky because the workflow forwards real bearer tokens through a management API.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The tool silently consumes management credentials from environment variables, which can cause privileged actions to occur without clear user awareness, especially in agent or automation contexts. Because this script can enumerate auth files, probe them, and optionally delete entries, undisclosed ambient credential use increases the risk of unintended high-privilege operations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Several user-facing progress messages are hardcoded in Chinese, which imposes a specific language on users without offering a language choice or documenting a locale-specific constraint. This matches the policy category for language or locale violations.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The manifest says execution requires the user to provide base_url and management_key before running, implying an explicit operator-supplied workflow. The code also sources base URL, management key, and management endpoints from environment variables, enabling operation with ambient configuration rather than only explicit user-provided inputs.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.