Back to skill

Security audit

Multi Agent Dev Team

Security checks for vulnerabilities and agentic risk

Overview

The skill’s main setup function is coherent, but it includes broad persistent optimization instructions and unsafe input handling that could affect OpenClaw configuration and workspace files.

Review carefully before installing. Use only in a trusted OpenClaw environment, avoid sensitive prompt or secret data in telemetry, do not enable the weekly optimizer unless you explicitly want cross-team configuration changes, and use simple alphanumeric team and role IDs until validation is fixed.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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
Findings (3)

T06 · System Persistence

Error
Location
SKILL.md:175
Finding
Mandatory recurring task persistently modifies cross-team configuration and stores telemetry<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:175-189` and duplicated at `SKILL.md:426-440` **Vulnerability Type**: Persistent scheduled configuration modification **Risk Level**: High ### Vulnerable Instructions ```markdown 2. **Skill learning telemetry** - Enable usage logging per agent/skill - Log format: `agent_id + skill_name + timestamp + context` 3. **Weekly optimization task (OpenClaw Cron)** - Create a weekly `openclaw cron` job in isolated session - Analyze last 7 days usage and update `openclaw.json` skill mapping - Always backup before writing config 4. **All-team scope** - Mechanism must apply to **all teams** (coding/wealth/other future teams) - No team-specific hardcoding in the optimizer 5. **Review outputs** - Save weekly optimization summary to `memory/YYYY-MM-DD.md` - Keep optimization history under `.lib/skill_analytics/` ``` ### Technical Analysis The skill explicitly marks a post-setup process as mandatory and directs the operator or agent to install a weekly OpenClaw cron task. That task is expected to analyze telemetry, rewrite `openclaw.json`, and save state under persistent memory and analytics directories. A scheduled task survives the original skill execution and performs future actions without requiring the setup wizard to be invoked again. Its required scope covers all current and future teams rather than only the team created during the current run. This creates persistent, cross-team configuration authority that is broader than the wizard's immediate purpose. The telemetry format also includes an unrestricted `context` field. Depending on what agents place in that field, persistent logs could retain source fragments, task data, file paths, user content, or other sensitive operational information. The instructions define neither redaction nor retention limits. The reviewed `wizard/setup.js` does not itself create this cron task. The issue resides in the mandatory skill instru ...[truncated 1369 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the requirement to install a recurring cron task as part of ordinary setup. 2. Make optimization explicitly opt-in and explain its scope before installation. 3. Scope each optimizer to a specific, validated team identifier rather than all teams. 4. Generate a proposed configuration diff and require affirmative user approval before every modification to `openclaw.json`. 5. Run the optimizer with only the minimum read and write permissions needed for its selected team. 6. Validate the current configuration version before writing to prevent overwriting concurrent changes. 7. Back up the configuration and provide a tested command that disables and removes the cron task. 8. Replace unrestricted telemetry context with a structured allowlist of non-sensitive fields. 9. Redact credentials, source content, personal data, prompts, and filesystem secrets before logging. 10. Define retention limits and provide deletion controls for `memory/` and `.lib/skill_analytics/`. 11. Document the cron job name, schedule, permissions, data inputs, outputs, and rollback procedure. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
wizard/setup.js:163
Finding
Unvalidated team name enables path traversal and regular-expression injection<![CDATA[ ## Vulnerability Details **File Location**: `wizard/setup.js:163-168`, `wizard/setup.js:438-446`, and `wizard/setup.js:512-514` **Vulnerability Type**: Path traversal and regular-expression injection **Risk Level**: High ### Vulnerable Code ```javascript const teamName = argTeam || await askDefault('Team name (用于区分多个团队)', 'default'); const teamPrefix = teamName === 'default' ? '' : `${teamName}-`; ok(`Team: ${teamName}`); ``` ```javascript // Remove old team agents (matching prefix) but keep main + other teams const prefixPattern = teamPrefix ? new RegExp(`^${teamPrefix}`) : null; config.agents.list = config.agents.list.filter(a => { if (a.default === true) return true; // If we have a prefix, only remove agents with that prefix if (prefixPattern) return !prefixPattern.test(a.id); // If default team, remove agents whose id matches any selected role OR old non-prefixed agents return false; // remove all non-main for default team }); ``` ```javascript const manifestDir = path.join(openclawPath, 'workspace', 'teamtask', 'teams'); fs.mkdirSync(manifestDir, { recursive: true }); const manifestPath = path.join(manifestDir, `${teamName}.json`); fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); ``` ### Technical Analysis The team name comes directly from the `--team` argument or interactive input and is not validated before being used in two security-sensitive contexts. First, it is interpolated directly into a `RegExp` constructor. Regular-expression metacharacters are consequently interpreted as syntax instead of literal team-name characters. A crafted value can make the prefix expression match agent IDs belonging to other teams. Invalid syntax can also throw an exception after the configuration backup has been created, causing setup failure. Second, the same value is passed to `path.join()` as part of the manifest filename. `path.join()` normalizes traversal components but does not enforce containment. A value containing ...[truncated 1751 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate team names immediately after reading CLI or interactive input: ```javascript const TEAM_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/; if (!TEAM_ID_RE.test(teamName)) { throw new Error( 'Team name must contain only letters, digits, underscores, and hyphens' ); } ``` 2. Avoid constructing a regular expression when literal prefix matching is sufficient: ```javascript const belongsToTeam = teamPrefix ? id => typeof id === 'string' && id.startsWith(teamPrefix) : () => false; ``` 3. If a regular expression is retained, escape every metacharacter before construction. Literal `startsWith()` comparison is preferable. 4. Resolve and verify the manifest destination before writing: ```javascript const manifestRoot = path.resolve(manifestDir); const manifestPath = path.resolve(manifestRoot, `${teamName}.json`); if ( manifestPath !== path.join(manifestRoot, `${teamName}.json`) || !manifestPath.startsWith(manifestRoot + path.sep) ) { throw new Error('Manifest path escapes the team manifest directory'); } ``` 5. Reject absolute paths, path separators, `.` components, and `..` components explicitly. 6. Validate agent IDs before filtering and show a preview of all entries that will be removed. 7. Require confirmation if any entry outside the exact selected team would be changed. 8. Write configuration atomically through a temporary file followed by a rename, and restore the backup automatically if validation or writing fails. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
wizard/setup.js:198
Finding
Unvalidated custom role ID enables agent workspace path traversal and instruction-file overwrite<![CDATA[ ## Vulnerability Details **File Location**: `wizard/setup.js:198-216`, `wizard/setup.js:457-471`, and `wizard/setup.js:484-495` **Vulnerability Type**: Path traversal through an untrusted role identifier **Risk Level**: High ### Vulnerable Code ```javascript const cId = await ask(' Role ID (lowercase, e.g. "ml-engineer"): '); if (!cId) { adding = false; break; } const cName = await askDefault(' Display name', cId); const cEmoji= await askDefault(' Emoji', '🔧'); const cDesc = await askDefault(' Description', `${cName} — custom role`); const cVibe = await askDefault(' Vibe', 'Professional'); const cResp = await ask(' Responsibilities (comma-separated): '); const modelTypeIdx = await choose(' Default model type', [ 'Strongest Reasoning', 'Code Specialized', 'Balanced', 'Fast', 'Long Context' ]); const modelTypes = ['strongest', 'code', 'balanced', 'fast', 'longContext']; selectedRoles[cId] = { id: cId, name: cName, emoji: cEmoji, category: 'custom', description: cDesc, defaultModel: modelTypes[modelTypeIdx], vibe: cVibe, responsibilities: cResp ? cResp.split(',').map(s => s.trim()) : [] }; ``` ```javascript for (const [roleId, role] of Object.entries(selectedRoles)) { const agentId = `${teamPrefix}${roleId}`; const isCodeArtisan = roleId === 'code-artisan'; const agentWS = isCodeArtisan ? path.join(openclawPath, 'agents', agentId, 'workspace') : workspace; newAgentIds.push(agentId); config.agents.list.push({ id: agentId, name: `${role.name} ${role.emoji}`, workspace: agentWS, model: { primary: agentModels[roleId].primary, fallbacks: agentModels[roleId].fallbacks, }, skills: ['teamtask'], }); } ``` ```javascript for (const [roleId, role] of Object.entries(selectedRoles)) { const agentId = `${teamPrefix}${roleId}`; const wsPath = path.join(openclawPath, 'agents', agentId, 'workspace'); if (!fs.existsSync(wsPath)) { fs.mkdirSync(wsPath, { recursive: true } ...[truncated 2787 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a strict role-ID format before adding the role: ```javascript const ROLE_ID_RE = /^[a-z0-9][a-z0-9-]{0,63}$/; if (!ROLE_ID_RE.test(cId)) { throw new Error( 'Role ID must contain only lowercase letters, digits, and hyphens' ); } ``` 2. Reject duplicate IDs, reserved IDs such as `main`, leading separators, absolute paths, `.` components, and `..` components. 3. Resolve the agents root and candidate workspace, then enforce containment: ```javascript const agentsRoot = path.resolve(openclawPath, 'agents'); const wsPath = path.resolve(agentsRoot, agentId, 'workspace'); if (!wsPath.startsWith(agentsRoot + path.sep)) { throw new Error('Agent workspace escapes the agents directory'); } ``` 4. Validate the final `agentId` after combining the team prefix and role ID. 5. Refuse to overwrite existing workspace files unless the user explicitly confirms replacement for the exact expected agent. 6. Write generated files atomically and use restrictive filesystem permissions where supported. 7. Validate all generated agent entries before modifying `openclaw.json`. 8. Add automated tests covering traversal strings, absolute paths, separators, reserved names, duplicate identifiers, and excessively long IDs. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (14)

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The README advertises that the wizard automatically modifies `openclaw.json`, workspaces, manifests, and sets up a weekly cron, but it does not clearly warn users that running the setup changes local files and installs persistent scheduled behavior. In a developer-tool skill, undocumented automated state changes can lead to unintended configuration drift, persistence, or disruption of existing environments, especially when users may run the command based only on the README.

Natural-Language Policy Violations

Medium
Confidence
85% confidence
Finding
The document is explicitly structured around only two languages, with separate '## English' and '## 中文' sections, and the activation examples also mix fixed English and Chinese commands. This creates a locale constraint without stating that users may choose another language or that the limitation is intentional for a region-specific purpose.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill mandates per-agent telemetry logging including agent_id, skill_name, timestamp, and context, but provides no minimization, consent, access control, or redaction guidance. Because 'context' may contain prompts, code, secrets, or personal data, this creates a realistic risk of sensitive data collection and later exposure through logs or downstream analytics.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
Requiring weekly optimization summaries in memory files and analytics history in a persistent directory encourages long-term retention of potentially sensitive operational data without any warning or controls. If summaries include task context, model behavior, or team activity details, they can become a durable source of confidential information leakage.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This is the Chinese-language repetition of the same telemetry requirement and has the same risk profile: it instructs persistent collection of agent skill usage events including context without privacy safeguards. Duplicating the requirement in another language broadens the chance that implementers will adopt insecure logging as standard practice.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This section directs persistent storage of optimization outputs and history, again without addressing sensitivity, retention, or access restrictions. Persistent archives can accumulate confidential prompts, architecture details, or usage patterns that materially increase blast radius if the workspace is read by other agents, users, or attackers.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
Many user-facing descriptions and workflow texts are written only in Chinese, while labels and names are mixed English/Chinese. This can violate language/locale policy if the skill presents one language by default without offering the user a language choice or documenting that the skill is intended for a Chinese-speaking context.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The collaboration and notes sections contain operational instructions entirely in Chinese, which effectively imposes a specific language/locale on downstream skill authors and users. The file does not provide an opt-in, alternative language, or justification that this template is intended only for a Chinese-language environment.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The wizard generates TOOLS.md stating agents can use shell execution, file editing, browser automation, and agent-spawn capabilities, but the created agent config only enables the 'teamtask' skill. This creates a security-significant mismatch between documented capabilities and actual configured permissions, which can mislead operators or downstream systems into assuming broader authority and trusting unsafe workflows or prompts.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The script overwrites the user's OpenClaw configuration, rewrites agent entries, creates agent workspace files, and writes team manifests after only a generic proceed prompt, without clearly enumerating the full scope of affected paths and destructive changes. In a security-sensitive local agent environment, unclear bulk modification of config and workspaces increases the risk of unintended privilege changes, agent exposure, or loss of prior configuration state.

Scope Creep

Low
Category
Excessive Agency
Content
- Set up a multi-role collaborative development team (2–10 agents)
- Need multiple teams to work in parallel with independent configurations
- Need custom collaboration workflows (not limited to standard 9-step)
- Need flexible role combinations and model assignments

### Quick Start
Confidence
70% confidence
Finding
Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Vague Triggers

Low
Confidence
81% confidence
Finding
This JSON manifest says users can define "fully custom roles via the wizard" without any stated constraints, examples, or exclusion conditions. In a manifest/context file, such unconstrained custom behavior can make the trigger scope or activation boundaries unclear compared with narrowly defined role templates.

Vague Triggers

Low
Confidence
87% confidence
Finding
The "custom" workflow is labeled "完全自定义协作步骤" with an empty steps array and no limitations or examples. For a manifest file, this is an ambiguous description of when and how the workflow should be used, increasing the chance of unintended or inconsistent invocation.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The prompt `Team name (用于区分多个团队)` imposes mixed-language UI text in a script that is otherwise English, without any user opt-in or explanation that the wizard is intended for a Chinese-speaking locale. This can violate language/locale policy guidance requiring choice or documented justification.

Static analysis

No suspicious patterns detected.