Back to skill

Security audit

Mainctrl

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed access-control skill, but it can weaken its own guardrail by automatically delegating blocked actions to unrestricted sub-agents and by using fragile exec and state handling.

Install only if you specifically want a workflow policy that blocks selected tools for main and automatically hands those blocked operations to other agents. Review the sub-agents' permissions first, avoid relying on the exec allow-except feature as a strong security boundary, and treat refresh-memory as a persistent change to future agent context.

Vulnerability Patterns
  • 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
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (5)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:171
Finding

Mandatory delegation redirects blocked operations to unrestricted sub-agents without renewed authorization

Content
View full analysis
Delegate this work to a sub-agent instead. > Use sessions_spawn to dispatch to coder, tester, auditor, or publicist. it MUST: 1. Briefly inform the user that the operation has been blocked and is being delegated. 2. Immediately spawn a sub-agent (coder, tester, auditor, or publicist) to complete the blocked operation. Do NOT wait for the user to confirm — report and delegate in the same turn. ``` ### Technical Analysis The Skill changes the controlled Agent's execution policy by requiring it to transfer blocked operations to a sub-agent immediately and explicitly forbidding renewed user confirmation. This is particularly significant because the documented architecture intentionally leaves agents outside `controlledAgents` unaffected by the tool restrictions. Consequently, blocking an operation at the main Agent does not necessarily prevent that operation. Instead, the Skill directs the Agent to move it to another execution context that may retain `write`, `edit`, `exec`, `process`, and `apply_patch` privileges. The Skill frontmatter limits automatic invocation, but once a user invokes the Skill and activates its behavior, the mandatory delegation instruction still replaces a denial with automatic privileged execution through another Agent. ### Attack Path 1. A user invokes the `mainctrl` Skill and enables blocking. 2. The main Agent attempts an operation involving a blocked tool. 3. The plugin rejects the tool call and returns the fixed delegation message. 4. The Skill instructions require the main Agent to spawn `coder`, `tester`, `auditor`, or `publicist` immediately. 5. No renewed user confirmation is requested for the delegated operation. 6. If the selected sub-agent i ...[truncated 719 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
plugin/index.js:72
Finding

Shell-naive exec allowlist permits compound-command bypasses

Content
View full analysis
cmd.includes(p)); if (blocked) { return { block: true, blockReason: `exec blocked: "${firstWord}" matched allow-except pattern "${blocked}". Delegate this work to a sub-agent instead.`, }; } return; // allowed } // Not in allow-except map → falls through to generic block below } ``` ### Technical Analysis The plugin determines whether an entire shell command is permitted by: 1. Extracting the first whitespace-delimited word. 2. Looking up that word in `execAllowExcept`. 3. Searching the complete command string for a small set of blocked substrings. 4. Permitting the entire command if none of those substrings appears. This is not shell-aware parsing. The default configuration for commands such as `ls`, `pwd`, and `cat` blocks redirection and pipes but does not block several common command-composition mechanisms, including: - Semicolon separators - Newline separators - `&&` - Backtick command substitution - `$()` command substitution for allowlisted commands other than `find` For example, the default `ls` configuration contains only `>`, `>>`, and `|`. A command such as the following starts with an allowlisted executable and does not match those patterns: ```sh ls ; destructive-command ``` The plugin therefore returns without blocking, leaving the complete command string to the `exec` tool. If that tool evaluate ...[truncated 1351 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
plugin/index.js:21
Finding

Missing or malformed state disables all tool-call enforcement

Content
View full analysis
0 ? state.controlledAgents : DEFAULT_CONTROLLED_AGENTS, blockedTools: Array.isArray(state.blockedTools) ? state.blockedTools : DEFAULT_BLOCKED_TOOLS, execAllowExcept: state.execAllowExcept && typeof state.execAllowExcept === "object" && !Array.isArray(state.execAllowExcept) ? state.execAllowExcept : DEFAULT_EXEC_ALLOW_EXCEPT, }; } catch { return { enabled: false, controlledAgents: DEFAULT_CONTROLLED_AGENTS, blockedTools: DEFAULT_BLOCKED_TOOLS, execAllowExcept: DEFAULT_EXEC_ALLOW_EXCEPT, }; } } ``` The disabled result is then accepted by the hook: ```js const state = readState(); // When the safety is off (enabled=false), allow everything if (!state.enabled) return; ``` ### Technical Analysis The security control explicitly defaults to `enabled: false` whenever: - The state file does not exist. - The file cannot be read. - JSON parsing fails. - Another exception occurs during state processing. This is a fail-open design. The state file is located inside the workspace Skill directory: ```js const STATE_FILE = resolve( homedir(), ".openclaw/workspace/skills/mainctrl/scripts/state.json" ); ``` An actor or Agent capable of modifying that workspace can disable enforcement ...[truncated 1248 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mainctrl.sh:109
Finding

Configuration commands accept syntactically valid values without enforcing the required schema

Content
View full analysis
'" >&2 echo "Example: mainctrl agents '[\"main\",\"coder\"]'" >&2 exit 1 fi # Validate JSON echo "$agents_json" | node -e "const{stdin}=process;let d='';stdin.on('data',c=>d+=c);stdin.on('end',()=>{try{JSON.parse(d)}catch(e){process.exit(1)}})" 2>/dev/null || die "invalid JSON array" local state state="$(read_state)" state="$(echo "$state" | node -e "const{stdin,stdout}=process;let d='';stdin.on('data',c=>d+=c);stdin.on('end',()=>{try{const s=JSON.parse(d);s.controlledAgents=JSON.parse(process.argv[1]);stdout.write(JSON.stringify(s))}catch(e){process.exit(1)}})" "$agents_json")" 2>/dev/null || die "failed to update agents" write_state "$state" echo "mainctrl: controlled agents updated" } ``` Equivalent syntax-only validation is used for `blockedTools` at lines 159-169 and `execAllowExcept` at lines 175-186. ### Technical Analysis The comments and usage messages claim that these commands require specific data structures, but validation only checks whether the supplied text can be parsed as JSON. It does not verify that: - `controlledAgents` is an array of non-empty strings. - `blockedTools` is an array containing recognized tool names. - `execAllowExcept` is an object. - Each `execAllowExcept` property is an array of strings. - Values have safe length and size limits. Some malformed structures are replaced with defaults by `readState()`, which can create behavior different from what the administrator requested. Other structures can reach the execution path. For example, an object-valued allow-except entry is truthy but does not implement `.find()`, causing an exception during the global `before_tool ...[truncated 1269 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Warning
Location
scripts/mainctrl.sh:190
Finding

Management command writes Skill-controlled content into persistent Agent memory

Content
View full analysis
"$tmpfile" node -e "const fs=require('fs');const newBlock=fs.readFileSync(process.argv[1],'utf8');const memFile=process.argv[2];let content='';try{content=fs.readFileSync(memFile,'utf8')}catch(e){}const m=content.match(/^### mainctrl 运行状态\\n+\x60{3}\\n[\\s\\S]*?\\n\x60{3}/m);if(m){content=content.slice(0,m.index)+newBlock+content.slice(m.index+m[0].length)}else{if(content){if(!content.endsWith('\\n'))content+='\\n';content+='\\n'+newBlock}else{content=newBlock}}fs.writeFileSync(memFile,content)" "$tmpfile" "$memory_file" rm -f "$tmpfile" echo "mainctrl: memory refreshed → $memory_file" } ``` ### Technical Analysis The `refresh-memory` command writes generated Skill content directly into: ```text ~/.openclaw/workspace/MEMORY.md ``` That file is intended to persist information across Agent sessions. Writing operational Skill content there creates a cross-session influence channel. The current generated block contains status output rather than a concealed payload, but the implementation gives the Skill an explicit mechanism to modify persistent Agent context. Several status fields originate from mutable state, including Agent identifiers and allow-except entries. These values are converted to text and inserted into the memory document without a trust-boundary distinction indicating that the content is untrusted configuration data. If later Agent behavior treats memory text as instructions, crafted state values could influence future sessions. ...[truncated 1185 chars]
Remediation
View remediation
Vulnerability Patterns
  • 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
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (64)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill is presented as a runtime safety guard, but the documented behavior materially exceeds that scope: it can install/remove a plugin, modify persistent state, write to a global MEMORY.md file, and disable protections entirely. That mismatch can mislead users and downstream agents into granting trust or invoking it under false assumptions, increasing the chance of unintended environment changes or weakened safeguards.

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 50)May include surrounding context.

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. Run `./scripts/mainctrl.sh status` to read the current runtime state.