Back to skill

Security audit

Codex Profile Orchestrator

Security checks for vulnerabilities and agentic risk

Overview

This skill is not clearly malicious, but it can copy account credentials into workspace files and automatically rewrite or remove authentication profiles.

Install only if you are comfortable giving it control over OpenClaw Codex authentication files. Run dry-run first, keep the workspace state directory private, inspect or disable apply/daemon behavior, and avoid using it on shared or synced workspaces unless token-bearing registry and backup files are protected or removed.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/codex_profile_orchestrator.py:61
Finding

OAuth Credentials Persisted in Plaintext Registry and Backup Files

Content
View full analysis

Vulnerability Details

File Location: scripts/codex_profile_orchestrator.py, lines 37-41, 61-68, 263-266, 286-295, 302-305, and 629-631
Vulnerability Type: Plaintext sensitive credential storage and unnecessary credential duplication
Risk Level: Medium

Vulnerable Code

python
def backup_file(path: Path) -> Path:
    backup_path = path.with_suffix(path.suffix + f'.bak-{int(time.time())}')
    if path.exists():
        shutil.copy2(path, backup_path)
    return backup_path
python
def extract_identity(profile_id: str, profile: dict[str, Any]) -> dict[str, Any]:
    token = profile.get('access') or profile.get('token')
    decoded = decode_token(token)
    auth_payload = decoded.get('https://api.openai.com/auth') or {}
    profile_payload = decoded.get('https://api.openai.com/profile') or {}
    return {
        'profileId': profile_id,
        'profileBlob': deep_copy(profile),
        'token': token,
python
if key in identities:
    record = identities[key]
    record['lastSeenAt'] = now_ms()
    record['profileBlob'] = deep_copy(row['profileBlob'])
python
identities[key] = {
    'email': row.get('email'),
    'userId': row.get('userId'),
    'accountId': row.get('accountId'),
    'canonicalId': canonical,
    'kind': kind,
    'firstSeenAt': now_ms(),
    'lastSeenAt': now_ms(),
    'profileBlob': deep_copy(row['profileBlob']),
}
python
for record in identities.values():
    canonical = record.get('canonicalId')
    profile_blob = record.get('profileBlob') or {}
    if canonical and canonical not in auth_profiles and profile_blob:
        auth_profiles[canonical] = deep_copy(profile_blob)
python
registry['lastPreferredProfileId'] = preferred_profile_id
registry['updatedAt'] = now_ms()
write_json(registry_path, registry) if apply else None

Technical Analysis

The orchestrator reads comp ...[truncated 3255 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove profileBlob and all token-bearing fields from the persistent registry. Store only the canonical profile ID, normalized identity attributes, profile kind, timestamps, and health metadata.
  2. Resolve profile credentials from the authoritative auth-profiles.json file at runtime instead of reconstructing profiles from registry copies.
  3. If credential persistence is strictly necessary, use an operating-system credential manager such as Windows Credential Manager or another secure secret-storage mechanism. Do not rely on plaintext workspace files.
  4. Create sensitive files with owner-only permissions and verify existing permissions before reading or writing them. On Windows, apply an ACL limited to the intended service account.
  5. Replace unrestricted timestamped backups with a bounded retention policy. Store backups in a protected directory, restrict their ACLs, and securely remove expired copies.
  6. Add a migration routine that removes profileBlob, access, refresh, and token fields from existing registry files.
  7. Add automated tests that inspect persisted registry and backup content and fail if recognizable bearer or refresh tokens are present.
  8. Continue redacting credentials from console output, but treat output redaction as an additional control rather than a substitute for secure storage.
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill description promises deterministic failover, account health selection, duplicate handling, auth profile inspection, and session sync, but the analyzed content does not substantiate those controls. This mismatch is dangerous because operators may trust the skill to make security-sensitive account or session decisions safely when the actual implementation may omit protections, leading to incorrect profile selection, unsafe rotation, or accidental disruption of authentication state.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
80% 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/codex_profile_orchestrator.py (reported line 361)May include surrounding context.

python
for key, entry in sessions.items():
        if not isinstance(entry, dict) or not key.startswith(prefix):
            continue
        if 'authProfileOverride' in entry or any(token in key for token in (':telegram:', ':signal:', ':discord:', ':whatsapp:', ':slack:', ':webchat:')):
            add(key)
    return out

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises operational behavior that implies file access, shell execution, configuration writes, and possible network interaction, but it declares no explicit tool scope or permission boundaries. In an agent environment, this increases the risk of over-privileged execution, unintended file modification, or command execution because consumers cannot reliably constrain what the skill is allowed to do.

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

python
def extract_identity(profile_id: str, profile: dict[str, Any]) -> dict[str, Any]:
    token = profile.get('access') or profile.get('token')
    decoded = decode_token(token)
    auth_payload = decoded.get('https://api.openai.com/auth') or {}
    profile_payload = decoded.get('https://api.openai.com/profile') or {}
    return {
        'profileId': profile_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/codex_profile_orchestrator.py (reported line 64)May include surrounding context.

python
def extract_identity(profile_id: str, profile: dict[str, Any]) -> dict[str, Any]:
    token = profile.get('access') or profile.get('token')
    decoded = decode_token(token)
    auth_payload = decoded.get('https://api.openai.com/auth') or {}
    profile_payload = decoded.get('https://api.openai.com/profile') or {}
    return {
        'profileId': profile_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/codex_profile_orchestrator.py (reported line 654)May include surrounding context.

python
def extract_identity(profile_id: str, profile: dict[str, Any]) -> dict[str, Any]:
    token = profile.get('access') or profile.get('token')
    decoded = decode_token(token)
    auth_payload = decoded.get('https://api.openai.com/auth') or {}
    profile_payload = decoded.get('https://api.openai.com/profile') or {}
    return {
        'profileId': profile_id,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script can automatically delete profiles from auth data after an invalid streak threshold without interactive confirmation or a stronger quarantine workflow. In a tool managing authentication profiles, this can cause destructive loss of account configuration, accidental lockout, or removal triggered by transient API/auth anomalies, especially because the file is rewritten in apply mode.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The skill performs outbound messaging through an external OpenClaw subprocess, which expands its behavior beyond local profile orchestration into external data transmission. Even though notifications appear intended for operations, they can disclose profile state, account aliases, session changes, and service-availability information to third-party channels, increasing privacy and exfiltration risk in a credential-management tool.

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_profile_orchestrator.py (reported line 507)May include surrounding context.

python
account = str(notify_cfg.get('account') or '').strip()
        if account:
            cmd.extend(['--account', account])
        result = subprocess.run(cmd, check=False, capture_output=True, text=True, timeout=90)
        if result.returncode == 0:
            state[key] = now
            sent.append(note)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

Several notification strings are written only in Turkish, which imposes a specific language on users without opt-in or documented locale constraints. This is a natural-language policy issue because the file does not provide any language selection or justification for the locale restriction.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
75% confidence
Finding

The manifest describes using the skill to stabilize or rebuild Codex switching logic, inspect profile files, select healthy accounts, and package safer replacement logic. The --daemon mode turns it into a persistent monitor that loops indefinitely, which is a materially broader operational capability than the described maintenance/orchestration tasks.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.