Back to skill

Security audit

OpenClaw OpenAI Multi Account

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its account-switching purpose, but it handles OAuth credentials with under-scoped network and file-path behavior that users should review before installing.

Install only if you are comfortable with a skill that can read and rewrite OpenClaw OAuth credentials across all configured agents. Avoid unattended use until the usage endpoint is pinned to a trusted HTTPS OpenAI/ChatGPT host and account names are validated to prevent path traversal. Treat the stored snapshot directory as sensitive credential storage.

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

Error
Location
scripts/openclaw-openai-accounts.py:681
Finding

OAuth Access Token Disclosure Through an Unrestricted Usage API Endpoint

Content
View full analysis
tuple[dict[str, Any], dict[str, Any]]: token = profile.get('access') account_id = profile.get('accountId') or current_identity(profile).get('accountId') if not token: return {}, {'status': 'auth-invalid', 'reason': 'missing-access-token'} headers = { 'Authorization': f'Bearer {token}', 'User-Agent': 'CodexBar', 'Accept': 'application/json', } if account_id: headers['ChatGPT-Account-Id'] = str(account_id) req = urllib.request.Request(CODEX_USAGE_URL, headers=headers, method='GET') try: with urllib.request.urlopen(req, timeout=timeout_sec) as resp: raw = resp.read().decode('utf-8', errors='ignore') ``` ### Technical Analysis The quota-probing function sends an OpenAI OAuth bearer access token in the `Authorization` header. It may also send the associated ChatGPT account ID. While the default endpoint is an expected `chatgpt.com` endpoint, the destination can be replaced without validation through the `OPENCLAW_CODEX_USAGE_URL` environment variable. The implementation does not: - Require HTTPS. - Restrict the hostname to an approved OpenAI domain. - Validate the destination path or origin. - Separate production credential-bearing requests from test endpoint overrides. - Explicitly prevent credential-bearing requests from following redirects to another origin. Consequently, any party capable of influencing the script's inherited environment can redirect quota probes to a server under tha ...[truncated 2112 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/openclaw-openai-accounts.py:282
Finding

Path Traversal in OAuth Credential Snapshot Names

Content
View full analysis
Path: return SNAPSHOT_DIR / f"{name}.json" ``` The generated path is used to write complete OAuth profiles: ```python def upsert_account_snapshot(meta: dict[str, Any], name: str, profile: dict[str, Any], *, saved_at: int | None = None, auto_discovered: bool | None = None) -> dict[str, Any]: accounts = meta.setdefault('accounts', {}) identity = current_identity(profile) sp = snapshot_path(name) write_json_atomic(sp, profile, mode=0o600) ``` It is also used to read and distribute profiles: ```python def cmd_use(name: str, model: str = "openai-codex/gpt-5.4", verify: bool = True, emit: bool = True) -> dict[str, Any]: snap = snapshot_path(name) if not snap.exists(): raise SystemExit(f"❌ 账号不存在: {name}") profile = json.loads(snap.read_text()) meta = sync_meta_with_reality() info = meta.get("accounts", {}).get(name, {}) identity = current_identity(profile) email_profile_id = email_profile_id_for_snapshot(info, profile) email = info.get('email') or identity.get('email') apply_auth_profile_selection(email_profile_id, email=email) propagate_profile(profile, email_profile_id) ``` The command-line arguments are accepted without validation: ```python p = sub.add_parser("capture") p.add_argument("name") p = sub.add_parser("add") p.add_argument("--name") p = sub.add_parser("use") p.add_argument("name") p.add_argument("--model", default="openai-codex/gpt-5.4") ``` ### Technical Analysis Account names are interpolated directly into a filesystem path: ```python SNAPSHOT_DIR / f"{name}.json" ``` No character allowlist, basename check, or resolved-path containment check is applied. A name containing directo ...[truncated 3065 chars]
Remediation
View remediation
str: if not ACCOUNT_NAME_RE.fullmatch(name): raise SystemExit("Invalid account name") if name in {".", ".."}: raise SystemExit("Invalid account name") return name ``` 2. Explicitly reject: - `/` and `\` path separators. - `.` and `..` path components. - Absolute paths. - Empty names. - Control characters and NUL bytes. 3. Enforce path containment as a second layer of defense: ```python def snapshot_path(name: str) -> Path: safe_name = validate_account_name(name) base = SNAPSHOT_DIR.resolve() candidate = (base / f"{safe_name}.json").resolve() if candidate.parent != base: raise SystemExit("Snapshot path escapes the profile directory") return candidate ``` 4. Apply validation uniformly to: - `capture` - `add --name` - `use` - names loaded from metadata before performing filesystem operations 5. Validate loaded profile structures before propagation. Require expected fields and types, including the intended provider and OAuth profile type, rather than accepting any JSON object. 6. Before overwriting an existing snapshot, ensure it is a regular file directly under `SNAPSHOT_DIR` and reject symbolic links. 7. Add tests covering traversal strings, absolute paths, backslash-based paths, Unicode separator edge cases, symlinks, and malicious metadata entries. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (30)

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

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The request destination is derived from OPENCLAW_CODEX_USAGE_URL, and the code attaches a live OAuth bearer token plus optional account identifier headers before making the outbound request. If an attacker can influence the environment, they can redirect the request to an attacker-controlled endpoint and exfiltrate authentication credentials and account metadata.

Content

Scanner excerpt · scripts/openclaw-openai-accounts.py (reported line 696)May include surrounding context.

python
req = urllib.request.Request(CODEX_USAGE_URL, headers=headers, method='GET')
    try:
        with urllib.request.urlopen(req, timeout=timeout_sec) as resp:
            raw = resp.read().decode('utf-8', errors='ignore')
            data = json.loads(raw) if raw.strip() else {}
    except urllib.error.HTTPError as e:

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documented behavior centers on account management, but the analyzed behavior includes outbound network access, subprocess execution, session inspection, and references to broken/undeclared functionality. This gap matters because the skill handles sensitive OAuth material and can switch active authentication state; undocumented network or command execution can expose credentials, alter local state unexpectedly, or fail in unsafe ways if users and reviewers were not informed.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Main script: `scripts/openclaw-openai-accounts.py`

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/test_openclaw_openai_accounts.py (reported line 70)May include surrounding context.

python
shutil.rmtree(self.root, ignore_errors=True)

    def env(self, *, primary_agent: str = "main") -> dict[str, str]:
        env = os.environ.copy()
        env["OPENCLAW_HOME"] = str(self.state)
        env["OPENCLAW_PRIMARY_AGENT"] = primary_agent
        env["HOME"] = str(self.root)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill advertises extensive capabilities involving credential management, file mutation, shell execution, and likely network access, but does not declare any tool scope or permission boundaries. In a security-sensitive skill that handles OAuth tokens and rewrites auth state across agents, missing explicit permissions increases the chance of over-broad execution and makes review, sandboxing, and user consent harder.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script emits multiple CLI messages in Chinese, starting with this line and continuing throughout the file, but does not provide language selection or indicate that the tool is intentionally Chinese-only. This creates a language/locale policy issue because the skill forces a specific language on all users without opt-in.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill performs live network calls to a remote service using stored OAuth credentials, which expands the attack surface and can disclose sensitive usage/account data to external infrastructure. In this skill context that behavior is partly expected for quota inspection, but it is still sensitive because it handles bearer tokens and account identifiers without clear trust-boundary restrictions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code builds an authenticated request using the saved access token and optional ChatGPT account ID, then sends it to a remote usage endpoint. While this network call is part of quota probing, there is no visible print/log message, prompt, docstring, or comment warning the user that account credentials and identifiers will be transmitted to an external service when probing status.

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/openclaw-openai-accounts.py (reported line 860)May include surrounding context.

python
cmd = ["openclaw", "models", "auth", "login", "--provider", "openai-codex"]
    if set_default_model:
        cmd.append("--set-default")
    subprocess.run(cmd, check=True)
    profile = current_profile()
    ident = current_identity(profile)
    guessed = name or ((ident.get("email") or "account").split('@', 1)[0])

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/openclaw-openai-accounts.py (reported line 1025)May include surrounding context.

python
def set_model_silently(model: str) -> int:
    cp = subprocess.run(
        ["openclaw", "models", "set", model],
        check=False,
        capture_output=True,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The code scans session history across agent workspaces to decide whether switching is safe, which can expose metadata about other conversations and workspaces beyond the current account operation. Even without exfiltration, this is a cross-workspace privacy boundary issue because unrelated session identifiers, timestamps, and model usage are inspected and surfaced in summaries.

Content

No source excerpt is available for this finding.

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/openclaw-openai-accounts.py (reported line 170)May include surrounding context.

python
header = {"alg": "none", "typ": "JWT"}
    payload = {
        "https://api.openai.com/profile": {"email": email, "email_verified": True},
        "https://api.openai.com/auth": {
            "chatgpt_account_id": account_id,
            "user_id": user_id,

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/openclaw-openai-accounts.py (reported line 171)May include surrounding context.

python
header = {"alg": "none", "typ": "JWT"}
    payload = {
        "https://api.openai.com/profile": {"email": email, "email_verified": True},
        "https://api.openai.com/auth": {
            "chatgpt_account_id": account_id,
            "user_id": user_id,

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

python
header = {"alg": "none", "typ": "JWT"}
    payload = {
        "https://api.openai.com/profile": {"email": email, "email_verified": True},
        "https://api.openai.com/auth": {
            "chatgpt_account_id": account_id,
            "user_id": user_id,

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

python
header = {"alg": "none", "typ": "JWT"}
    payload = {
        "https://api.openai.com/profile": {"email": email, "email_verified": True},
        "https://api.openai.com/auth": {
            "chatgpt_account_id": account_id,
            "user_id": user_id,

Static analysis

No suspicious patterns detected.