Back to skill

Security audit

Agentic Loop Upgrade

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-related rather than malicious, but it needs review because it can wrap agent behavior, reuse host LLM credentials, persist task context, and lets risky actions proceed after an approval timeout.

Review before enabling, especially on production agents or agents with broad tool access. Treat the approval timeout as fail-open unless patched or configured to deny on timeout, restrict LLM endpoints to approved provider origins, and assume local state/checkpoints may contain sensitive task context. Use the Mode dashboard opt-in carefully and verify the installed hook actually matches the documented integration.

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
src/execution/approval-gate.ts:138
Finding
Approval Gate Fails Open for High-Risk and Critical Operations<![CDATA[ ## Vulnerability Details **File Location**: `src/execution/approval-gate.ts:138-144, 202-230`; execution path in `src/orchestrator.ts:249-278` **Vulnerability Type**: Fail-open authorization timeout **Risk Level**: High ### Vulnerable Code ```typescript const DEFAULT_CONFIG: ApprovalGateConfig = { enabled: true, timeoutMs: 10000, // 10 seconds requireApprovalFor: ["high", "critical"], autoApproveLowRisk: true, autoDenyCritical: false, }; ``` ```typescript // Wait for decision or timeout const decision = await this.waitForDecision(request); const waitedMs = Date.now() - startTime; // Update request request.decision = decision; request.decidedAt = Date.now(); request.decidedBy = decision === "timeout" ? "timeout" : "human"; // Cleanup this.pendingRequests.delete(request.id); this.resolvers.delete(request.id); // Notify listeners this.config.onDecision?.(request); return { proceed: decision === "approved" || decision === "timeout", decision, request, waitedMs, }; ``` The resulting decision is directly trusted by the orchestrator: ```typescript if (this.config.approvalGate.enabled && this.approvalGate.requiresApproval(tool)) { const approval = await this.approvalGate.requestApproval(tool); if (!approval.proceed) { wasBlocked = true; blockReason = `Tool blocked: ${approval.decision} - ${approval.request.riskReason}`; return { result: { id: tool.id, success: false, error: blockReason }, wasRetried: false, retryAttempts: 0, wasBlocked: true, blockReason, stepCompleted: false, }; } } ``` ### Technical Analysis The approval mechanism treats a timeout as equivalent to affirmative authorization. The default configuration requires approval for both `high` and `critical` operations, but `autoDenyCritical` is disabled and the final decision sets `proceed` to `true` when the request times out. Consequently, the gate does not actually require positive user consent. Missing, delay ...[truncated 1581 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat timeout as denial: ```typescript proceed: decision === "approved" ``` 2. Default `autoDenyCritical` to `true`. 3. Require explicit, authenticated approval for all high and critical actions. 4. Never auto-proceed when no `onApprovalNeeded` handler is registered. 5. Bind each approval to the originating user, session, exact tool name, and immutable argument digest. 6. Expire approval requests without executing them and require a new request if arguments change. 7. Add tests confirming that timeout, callback failure, UI disconnection, process suspension, and malformed responses all fail closed. 8. Consider requiring re-authentication or a second confirmation for critical and irreversible operations. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/llm/caller.ts:52
Finding
Host API Credentials Can Be Forwarded to an Arbitrary Configured Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `src/llm/caller.ts:52-110, 142-153, 180-188, 226-243, 278-296` **Vulnerability Type**: Credential disclosure through unrestricted endpoint configuration **Risk Level**: High ### Vulnerable Code The caller automatically resolves credentials from process environment variables and host authentication files: ```typescript function resolveApiKey(config?: LLMCallerConfig): string | null { // 1. Explicit config (from enhanced-loop-hook, which resolves via auth profile chain) if (config?.apiKey) return config.apiKey; // 2. Environment variable fallbacks if (process.env.ANTHROPIC_API_KEY) return process.env.ANTHROPIC_API_KEY; if (process.env.OPENAI_API_KEY) return process.env.OPENAI_API_KEY; // 3. Try to read from OpenClaw auth storage const home = process.env.HOME || process.env.USERPROFILE || ""; const authPaths = [ path.join(home, ".openclaw", "agents", "main", "agent", "auth-profiles.json"), path.join(home, ".openclaw", "auth-profiles.json"), path.join(home, ".config", "openclaw", "auth-profiles.json"), ]; for (const authPath of authPaths) { try { if (!fs.existsSync(authPath)) continue; const content = fs.readFileSync(authPath, "utf-8"); const auth = JSON.parse(content); const profiles = auth.profiles || {}; const providersInPriorityOrder = [config?.provider, "anthropic", "openai-codex", "openai"] .filter((p): p is string => Boolean(p)); for (const provider of providersInPriorityOrder) { const order = auth.order?.[provider] as string[] | undefined; if (order?.length) { for (const profileId of order) { const p = profiles[profileId] as { provider?: string; type?: string; key?: string; token?: string; apiKey?: string; access?: string; } | undefined; if (!p || p.provider !== provider) con ...[truncated 4362 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind credentials to explicit provider identities and approved endpoint origins. 2. Allowlist official provider hosts by default, such as the exact required Anthropic and OpenAI API origins. 3. Require explicit administrator opt-in for custom endpoints. 4. Enforce HTTPS for all non-loopback production requests. 5. Never attach automatically resolved host credentials to an unknown or custom origin. 6. Require a separate credential to be configured for each custom endpoint. 7. Reject provider and credential mismatches instead of falling back across unrelated providers. 8. Consider blocking loopback, link-local, private-network, and metadata-service destinations unless explicitly required. 9. Redact known secret patterns from prompt context and tool arguments before transmission. 10. Add audit logging that records the destination origin and provider without logging credentials or full prompt bodies. 11. Add tests proving that credentials are not sent after redirects to unapproved origins. 12. Disable automatic redirect following or validate every redirect destination before forwarding authorization headers. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/state/persistence.ts:291
Finding
Conversation-Derived State Is Persisted Without Explicit Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `src/state/persistence.ts:291-310`; related checkpoint writes in `src/state/checkpoint.ts:362-377` **Vulnerability Type**: Insecure local storage of sensitive task data **Risk Level**: Medium ### Vulnerable Code ```typescript /** * Save state to disk */ async save(): Promise<void> { if (!this.state || !this.dirty) return; await fs.mkdir(this.config.stateDir, { recursive: true }); const filePath = this.getStatePath(this.state.sessionId); await fs.writeFile(filePath, JSON.stringify(this.state, null, 2)); this.dirty = false; } /** * Load state from disk */ async load(sessionId: string): Promise<PlanState | null> { const filePath = this.getStatePath(sessionId); try { const content = await fs.readFile(filePath, "utf-8"); return JSON.parse(content) as PlanState; } catch { return null; } } ``` The checkpoint manager uses the same pattern: ```typescript private async saveCheckpoint(checkpoint: CheckpointData): Promise<void> { const sessionDir = this.getSessionDir(checkpoint.sessionId); await fs.mkdir(sessionDir, { recursive: true }); const filePath = path.join(sessionDir, `${checkpoint.id}.json`); await fs.writeFile(filePath, JSON.stringify(checkpoint, null, 2)); } ``` ### Technical Analysis The Skill persists plans and checkpoints to local JSON files but does not specify directory or file modes. Effective access therefore depends on the process umask, existing parent-directory permissions, and platform defaults. Persisted structures can contain user goals, generated plan steps, step results, error details, metadata, conversation summaries, and operational context. These values may reveal confidential project details, filesystem locations, commands, infrastructure names, or other sensitive information. The state is later loaded and inserted into Agent context. Although session identifiers are sanitized for path construction, the implementation does not validate f ...[truncated 1426 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create state and checkpoint directories with mode `0700`. 2. Create state files with mode `0600` and verify permissions after creation. 3. Validate that directories and files are owned by the expected host user before reading or writing. 4. Reject symbolic links by using safe open flags and checking file metadata. 5. Use atomic writes: create a securely permissioned temporary file in the same directory, flush it, then rename it over the destination. 6. Add configurable retention periods and automatic deletion of obsolete state. 7. Redact secrets and unnecessary tool output before persistence. 8. Provide an option to disable persistence for sensitive sessions. 9. Consider authenticated encryption for state that must remain confidential at rest. 10. Treat loaded state as untrusted data and delimit or sanitize it before inserting it into Agent context. ]]>
Vulnerability Patterns
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (156)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
To disable immediately:
```bash
# Option 1: Delete config (disables enhanced loop, keeps skill installed)
rm ~/.openclaw/agents/main/agent/enhanced-loop-config.json

# Option 2: Set enabled=false in config
# Option 3: Mode dashboard → Core Loop → Save
Confidence
85% 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).

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description suggests a sophisticated orchestration/agent runtime with planning, parallelism, recovery logic, confidence controls, state-machine observability, and a UI. The supplied code does none of that. It is a command-line analysis and visualization script for a task hierarchy JSON file. Its behavior is limited to loading a file, traversing nested tasks, computing summary statistics, and printing representations in ASCII, DOT, or JSON. This is a materially different primary purpose, so the description does not accurately represent the code.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description describes a substantial orchestration/agent framework with execution features and a UI. The supplied code does not implement any of those capabilities. It is narrowly focused on offline validation of a plan JSON file from stdin or disk. While plan validation could be a supporting utility within a larger planning system, this code chunk itself materially differs in primary purpose and lacks the advertised runtime, recovery, observability, parallelism, and UI behavior. Therefore the description does not accurately represent this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description presents the skill as implementing an enhanced agentic loop with planning/execution/state-machine functionality and a configuration UI. The supplied code chunk does not implement those runtime agent features; instead, it performs verification and auditing of an installation. This is a materially different primary purpose. While such a script could be a supporting utility for the skill, the chunk itself exercises undeclared auditing capabilities (filesystem inspection, optional network syscall tracing, and source-code scanning) that are not represented in the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description describes a substantial agent orchestration and UI feature set, but the supplied code only resolves a filesystem path using environment variables and the user's home directory. This is a materially different primary purpose. While accessing environment variables and constructing a local path is benign, it does not implement or meaningfully support the described planning/loop/dashboard capabilities in this chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The supplied code chunk is focused on proactive context management, not an agentic loop framework. It manages token budgets, prunes and summarizes messages, stores and searches working memory, and injects prior context into future prompts. While this could support a larger agentic system, the claimed headline capabilities—planning, parallel execution, confidence gating, semantic error recovery, observable state machine, and Mode dashboard UI—are not implemented in this code. This is a material description-to-behavior mismatch because the declared purpose emphasizes orchestration and UI features, whereas the actual code provides only context/memory management infrastructure.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description describes a broad orchestration/agent runtime with planning, parallelism, confidence-based control, recovery mechanisms, state observability, and UI support. The supplied code does none of those things. Its sole purpose is context-window management through message token estimation and summarization of older chat history. While it does include a basic fallback from LLM-based summarization to heuristic summarization, that is not equivalent to the claimed semantic error recovery. This is a clear description-behavior mismatch because the actual primary purpose is materially different from the declared one.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description describes a substantial orchestration system with advanced runtime behaviors and a configuration UI. The supplied code chunk is limited to type declarations for resolving a local agent directory path and a deprecated alias. This is a materially different primary purpose and indicates undeclared filesystem/path utility behavior unrelated to the claimed agentic loop features.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description describes a complex orchestration/agent runtime feature set and UI, but the provided code only implements a filesystem path helper. Its primary purpose is materially different from the declared purpose. While the code is benign and limited, it does access environment variables and the OS home directory to construct a local path, which is not reflected in the description. Therefore this is a clear description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The code mainly reads a JSON config file, merges it with defaults, checks whether the feature is enabled, and if enabled returns a wrapper whose runtime behavior is limited to console logging and calling the original runner unchanged. The comments explicitly state this is only an initial/simple wrapper and that full integration of planning, parallel execution, and related features is not implemented. While the defaults contain configuration fields for the declared features, merely storing config options does not realize those capabilities. The declared description therefore materially overstates what the code chunk actually does, especially the core agentic loop enhancements and the dashboard UI.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding
The declared description emphasizes an agentic execution loop with planning, parallel execution, confidence gates, semantic recovery, state-machine observability, and a dashboard UI. The supplied code chunk instead focuses on context-window management and working-memory utilities. While context management could support an agentic loop, it is a distinct capability and the primary behavior shown here is not represented in the description. There is also no evidence in this chunk of the specifically declared features such as planning, parallel execution, confidence gates, state-machine observability, or UI/dashboard functionality. Therefore the description does not accurately represent this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The supplied code chunk is focused on proactive context management, not an agentic loop framework. It estimates token usage, maintains a token budget, stores and searches working memory, prunes old messages, summarizes pruned tool results/work sessions, and injects retrieved context. None of the prominently declared capabilities—planning, parallel task execution, confidence-based gating, semantic error recovery, observable state machine behavior, or a dashboard UI—are present in this code. This is a material description/behavior mismatch rather than a minor implementation-detail gap.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description emphasizes a sophisticated agentic loop system with planning, parallelism, confidence gating, error recovery, observability, and a UI dashboard. The supplied code chunk does not implement those capabilities. Instead, it is specifically a TypeScript declaration for a context summarizer that manages conversation history length by estimating tokens, summarizing old messages, condensing tool results, and optimizing message arrays. This is a materially different primary purpose from the declared description, so it should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The code chunk is narrowly focused on managing context window size through token estimation, summarization of old messages, tool-result condensation, and rebuilding a shortened message list. It does not implement an agentic loop, planning, parallel task execution, confidence thresholds/gates, semantic recovery logic, state-machine observability, or any dashboard/UI elements. This is a material description-behavior mismatch because the declared purpose describes a substantially different system than the code provided.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Most of the declared backend/orchestration capabilities are represented in the code: planning, reflection/replanning, confidence gates, error-recovery support, context management hooks, and an observable state machine. However, the description explicitly claims 'Includes Mode dashboard UI for easy configuration,' and there is no UI-related code here at all. Additionally, the main run loop is a simplified/demo orchestrator that does not actually invoke real tool execution, parallel tool execution, or recovery in-line; those capabilities exist as separate helper methods rather than being fully exercised by the primary loop. This makes the description somewhat broader than the actual supplied chunk. Because the missing UI is a materially undeclared/overstated capability in the provided code chunk, this should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The code chunk is specifically about approval gates for risky tool calls, including risk classification, pending approval requests, human approve/deny actions, timeout behavior, and an execution wrapper that can block tools. While the declared description mentions 'confidence gates,' that is not the same as a human approval interception system, and the other advertised features—planning, parallel execution, semantic error recovery, observable state machine, and Mode dashboard UI—are not represented in this code. This indicates the code’s behavior is materially different from the declared purpose rather than merely being a supporting implementation detail.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The supplied code is narrowly focused on approval gating for risky tool executions, not on an agentic loop, planning, parallel execution, confidence gating in the reasoning sense, semantic error recovery, observable state machines, or a dashboard UI. While one could loosely argue this is a kind of 'gate,' the concrete functionality is materially different: it intercepts tools, classifies risk, waits for human approval or timeout, and blocks/allows execution. Those are significant undeclared capabilities and the primary purpose does not match the stated description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
83% confidence
Finding
The supplied code chunk accurately supports the 'semantic error recovery' portion of the description, including diagnosing failures and adapting retries or escalation. However, it does not implement the other prominently declared capabilities: no planning logic, no parallel execution, no confidence gating, no observable state machine, and no UI/dashboard integration. This is a description-behavior mismatch because the declared purpose presents a broader composite skill than what this code chunk actually provides.

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding
The supplied code supports only one portion of the description: parallel execution of tool calls with dependency classification and metrics. There is no evidence in this chunk of planning logic, confidence-based gating, semantic error recovery, observable state-machine behavior, or any dashboard/UI integration. Because the declared description presents a broader primary capability set than the code actually implements, the description does not accurately represent this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The code chunk only covers one narrow aspect of the description: semantic/automatic error recovery via retries and alternative approaches. It does not implement an agentic loop, planning, parallel task execution, confidence-based gating, a state machine, or any dashboard/UI configuration layer. Because the declared purpose presents a broader system with several major capabilities absent from the supplied code, the description does not accurately represent what this code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
87% confidence
Finding
The declared description mostly aligns with the package’s core purpose: it is clearly an enhanced agentic loop and the code supports planning, parallel execution, confidence gates, semantic/error recovery, and an observable state machine. However, the description omits several substantial capabilities exposed by the code, including persistent state management, step tracking, approval gates, checkpointing, context summarization, task-stack orchestration, and LLM caller utilities. More importantly, the description explicitly claims a 'Mode dashboard UI for easy configuration,' but this code chunk only shows library exports and no UI-related modules or dashboard functionality. Because the description both misses material capabilities and includes a notable unsupported UI claim, it does not accurately represent the supplied code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description is for a high-level enhanced agentic loop with orchestration and UI capabilities. The supplied code chunk instead is a low-level LLM transport/client module. Its primary behavior is credential resolution and API invocation for Anthropic/OpenAI-compatible providers, including reading local auth profile files, consuming environment variables, and making external HTTP requests. Those are materially different behaviors from the declared planning/state-machine/dashboard functionality, and the code chunk does not demonstrate the advertised orchestration features. Therefore this description does not accurately represent this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The code is a lightweight hook/bootstrapper: it reads an enhanced-loop JSON config from disk, caches it, checks whether the feature is enabled, and returns a wrapper that only logs messages and calls the original runner unchanged. Although default configuration fields mention planning, execution, context, errorRecovery, and stateMachine, these are not operationalized anywhere in the code. The comments explicitly say the current version 'just run[s] the original' and that full integration would come later. Therefore the declared description materially overstates the implemented behavior. There is no evidence of the claimed dashboard UI either.

Tp4

High
Category
MCP Tool Poisoning
Confidence
80% confidence
Finding
The code broadly matches an orchestrator for an enhanced agent loop: planning, step tracking, approvals, retries, context summarization, checkpointing, resume, and status callbacks are all present. However, the declared description includes several specific capabilities that are not supported by this code chunk as shown. There is no visible API for parallel execution, only sequential step/progress handling. 'Confidence gates' are not represented; instead, the code has approval gates based on risk levels. 'Semantic error recovery' is only weakly suggested by retry with alternatives, which is narrower and not clearly semantic. An 'observable state machine' is also overstated: while there are callbacks and status accessors, no explicit state machine abstraction appears. Finally, the claimed Mode dashboard UI/configuration is absent from this file, aside from formatting helpers for possible UI rendering. Therefore the description overstates and partially mischaracterizes the actual behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The code largely matches an enhanced orchestration loop, including plan generation, approval gating, retries, context summarization, checkpoints, resume, and status formatting. However, several prominently declared capabilities are not evidenced in this chunk. There is no implementation of parallel execution; tool execution is single-path via executeTool. The 'approval gate' is risk/approval based, not a confidence gate driven by model confidence thresholds. Error handling uses retry/checkpoint behavior and some heuristic step completion, but not a clearly semantic error recovery system. The code maintains state and provides status getters/formatters, but does not expose an observable state machine in the sense of explicit state machine transitions/events. Finally, while it outputs a special :::plan block for UI parsing, there is no Mode dashboard UI or configuration UI implementation in this code. Because these are central advertised features rather than minor omissions, the description overstates the implemented behavior.

Static analysis

Detected: suspicious.env_credential_access, suspicious.potential_exfiltration, suspicious.prompt_injection_instructions

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/verify.sh:97

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
src/dist/llm/caller.js:20

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
src/llm/caller.ts:57

Sensitive-looking file read is paired with a network send.

Warn
Code
suspicious.potential_exfiltration
Location
src/dist/llm/caller.js:35

Sensitive-looking file read is paired with a network send.

Warn
Code
suspicious.potential_exfiltration
Location
src/llm/caller.ts:71

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
references/context-management.md:140

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
references/task-hierarchy.md:235