Back to skill

Security audit

OC Guard

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent OpenClaw configuration guard, but it handles high-impact config and credentials with under-scoped external AI use and unsafe local artifact storage.

Review before installing. Use --proposal with a reviewed local JSON file instead of putting secrets in natural-language requirements, avoid embedding credentials in parent-object changes, and assume /tmp/oc-guard-* files and receipts may contain sensitive config until the redaction and temp-file handling are fixed. Apply should be run only by someone authorized to change OpenClaw agent, tool, plugin, channel, and gateway behavior.

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
` or the corresponding apply command. 3. The path `/channels/feishu/accounts/example` passes the mutation allowlist. 4. `mask_value()` examines only that path and finds no secret keyword. 5. The complete `value` object, including `appSecret`, is placed in the `applied` report. 6. The secret is printed in the execution receipt. 7. The raw proposal is additionally stored at `/tmp/oc-guard-last-proposal.json`. 8. Anyone with access to captured output or the temporary artifact may recover the credential. The s ...[truncated 1034 chars]:104
Finding

Nested configuration secrets are disclosed in receipts and temporary proposal files

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/oc-guard.py:26
Finding

Predictable shared temporary files allow symlink attacks and insecure artifact exposure

Content
View full analysis
None: line = f"[{dt.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {msg}" LOG_PATH.parent.mkdir(parents=True, exist_ok=True) with LOG_PATH.open("a", encoding="utf-8") as f: f.write(line + "\n") ``` The error path is overwritten directly: ```python def fail(msg: str, code: int = 1, status: str = "失败") -> None: ERROR_PATH.write_text(msg + "\n", encoding="utf-8") log(f"ERROR: {msg}") raise GuardError(msg, status=status, code=code) ``` Diagnostic output is also written to a fixed name: ```python OPENCODE_DEBUG_PATH.write_text( json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8", ) ``` Plan and proposal artifacts are written in the same manner: ```python LAST_PROPOSAL_PATH.write_text( json.dumps(proposal, ensure_ascii=False, indent=2) + "\n", encoding="utf-8" ) LAST_PLAN_PATH.write_text( json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8" ) ``` ```python dump_json(LAST_PROPOSAL_PATH, proposal) ``` ### Technical Analysis The application writes multiple artifacts to fixed, publicly predictable names under `/tmp`. The write operations use normal ...[truncated 2891 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (18)

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/oc-guard.py (reported line 499)May include surrounding context.

python
temp_home = Path(td)
        temp_cfg = temp_home / "openclaw.json"
        dump_json(temp_cfg, cfg)
        env = os.environ.copy()
        env["OPENCLAW_CONFIG_PATH"] = str(temp_cfg)
        proc = run([str(OPENCLAW_BIN), "config", "validate", "--json"], timeout=30, check=False, env=env)
        out = ((proc.stdout or "") + (proc.stderr or "")).strip()

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Line L212 instructs agents to use bilingual phrasing wherever the repository already does so, effectively imposing a language/locale behavior by default. The file does not indicate this is optional, user-selectable, or required for a documented region-specific compliance reason, which matches the language-policy violation criterion.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 88)May include surrounding context.

bash
chmod +x scripts/oc-guard
mkdir -p ~/.local/bin
ln -sf "$PWD/scripts/oc-guard" ~/.local/bin/oc-guard

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill invokes external commands and implies file-changing behavior, but it does not declare any explicit tool scope such as allowed tools or permissions. This creates an authorization gap where an agent may use shell, file read/write, or environment access more broadly than intended, increasing the chance of unintended command execution or config modification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The instruction return 【模型说明-未执行】`` forces a specific language/locale in the skill's natural-language behavior. The file does not offer the user a language choice or explain a justified region-specific requirement, so this is a language policy violation.

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/oc-guard.py (reported line 91)May include surrounding context.

python
def run(cmd, timeout=60, check=True, env=None):
    return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout, check=check, env=env)


def load_json(path: Path):

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill sends natural-language requirements to an external AI tool to generate configuration changes that may later be applied to live OpenClaw configuration. Even though downstream path allowlisting and validation exist, this creates an indirect prompt-injection and unsafe-automation boundary where untrusted user text can influence security-sensitive config proposals, including channels, bindings, models, plugins, and tools.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The prompt text instructing the proposal generator is written in Chinese and other user-facing strings throughout the script also require or assume Chinese output. There is no opt-in or language-selection mechanism, so the skill effectively forces a specific language/locale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

User-supplied natural-language requirements are forwarded to an external subprocess without any explicit notice, consent, or boundary warning in the workflow. In a security-sensitive config-management skill, that increases the risk of unintended disclosure of internal architecture, tokens, account names, or operational details embedded in user requests.

Content

No source excerpt is available for this finding.

Tainted flow: 'payload' from os.environ.get (line 591, credential/environment) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/oc-guard.py (reported line 596)May include surrounding context.

python
"stdout": stdout,
            "stderr": stderr,
        }
        OPENCODE_DEBUG_PATH.write_text(
            json.dumps(payload, ensure_ascii=False, indent=2) + "\n",
            encoding="utf-8",
        )

Tainted flow: 'payload' from os.environ.get (line 609, credential/environment) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/oc-guard.py (reported line 616)May include surrounding context.

python
"extracted_json": text,
            "parse_error": str(e),
        }
        OPENCODE_DEBUG_PATH.write_text(
            json.dumps(payload, ensure_ascii=False, indent=2) + "\n",
            encoding="utf-8",
        )

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

After applying config, the skill performs live canary executions against agents, which can trigger real model/tool behavior under the new configuration. In this context, agent configs may enable external network access, tool use, or integration side effects, so an apply operation can cause unintended outbound actions or data exposure beyond mere validation.

Content

No source excerpt is available for this finding.

Tainted flow: 'backup_file' from os.environ.get (line 773, credential/environment) → shutil.copy2 (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/oc-guard.py (reported line 775)May include surrounding context.

python
ts = dt.datetime.now().strftime("%Y%m%d_%H%M%S")
    backup_file = BACKUP_DIR / f"openclaw.json.{ts}.bak"
    dump_json(LAST_PROPOSAL_PATH, proposal)
    shutil.copy2(config_file, backup_file)
    dump_json(config_file, modified)

    log(f"Backup created: {backup_file}")

Tainted flow: 'backup_file' from os.environ.get (line 773, credential/environment) → shutil.copy2 (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/oc-guard.py (reported line 784)May include surrounding context.

python
restarted = run([str(OPENCLAW_BIN), "gateway", "restart"], timeout=60, check=False)
    if restarted.returncode != 0:
        log("Gateway restart failed, rolling back")
        shutil.copy2(backup_file, config_file)
        run([str(OPENCLAW_BIN), "gateway", "restart"], timeout=60, check=False)
        fail("restart failed after apply; rolled back")

Tainted flow: 'backup_file' from os.environ.get (line 773, credential/environment) → shutil.copy2 (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/oc-guard.py (reported line 791)May include surrounding context.

python
restarted = run([str(OPENCLAW_BIN), "gateway", "restart"], timeout=60, check=False)
    if restarted.returncode != 0:
        log("Gateway restart failed, rolling back")
        shutil.copy2(backup_file, config_file)
        run([str(OPENCLAW_BIN), "gateway", "restart"], timeout=60, check=False)
        fail("restart failed after apply; rolled back")

Tainted flow: 'backup_file' from os.environ.get (line 773, credential/environment) → shutil.copy2 (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/oc-guard.py (reported line 799)May include surrounding context.

python
restarted = run([str(OPENCLAW_BIN), "gateway", "restart"], timeout=60, check=False)
    if restarted.returncode != 0:
        log("Gateway restart failed, rolling back")
        shutil.copy2(backup_file, config_file)
        run([str(OPENCLAW_BIN), "gateway", "restart"], timeout=60, check=False)
        fail("restart failed after apply; rolled back")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The canary message uses a Chinese instruction (请仅回复) to direct agent behavior, reflecting a fixed language assumption. Because the script provides no language choice or locale opt-in, this is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
75% confidence
Finding

This manifest contains user-facing natural language in Chinese, including the post-check expectation on L15, but provides no indication that language selection is optional or that the skill is intentionally limited to a Chinese-speaking environment. Under the policy, locale or language constraints should be documented or offer user opt-in to avoid implicit language forcing.

Content

No source excerpt is available for this finding.