T09 · Insecure Skill Coding Practices
- Location
scripts/execute.py:73- Finding
OpenClaw Command Injection Through Unescaped Execution-Plan Content
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This multi-agent orchestration skill is not clearly malicious, but it needs Review because it delegates work broadly and has unsafe command/path handling plus retained sessions that are not clearly disclosed.
Install only after reviewing the generated execution commands and understanding that task details may be sent to multiple agents or profiles. Avoid using sensitive data unless you have confirmed where spawned sessions, mission files, logs, and reports are stored and how to delete them. Run the scripts with least privilege and treat subtasks JSON, mission IDs, and execution_plan.json as trusted inputs only.
scripts/execute.py:73OpenClaw Command Injection Through Unescaped Execution-Plan Content
scripts/execute.py:19Mission Path Traversal and Untrusted Mission-Path Redirection
scripts/consolidate.py:31Agent Output Path Traversal Through Unvalidated Plan Identifiers
scripts/assemble.py:156Spawned Agent Sessions Are Retained Contrary to the Advertised Cleanup Policy
설명은 엔드투엔드 멀티에이전트 오케스트레이션을 약속하지만, 제공된 코드 조각은 주로 '계획 수립기' 역할이다. decompose_task는 빈 리스트를 반환하며 자동 분해가 구현되지 않았고, --task만 주어지면 분해가 필요하다고 안내만 한다. 또한 sessions_spawn/sessions_send를 실제 호출하지 않고 해당 호출용 파라미터를 execution_plan.json에 기록할 뿐이어서 에이전트를 즉석 생성하거나 병렬 실행하지 않는다. 의존성 기반 phase 계산은 병렬 가능성을 표시하지만 실제 실행 엔진은 없다. 마지막으로 결과를 수집·통합하는 로직도 없다. 따라서 선언된 핵심 기능 대비 실제 동작이 materially 부족하여 설명-행동 불일치로 판단된다.
설명은 멀티에이전트 시스템 전체를 자동 오케스트레이션하는 핵심 기능(태스크 분해, 에이전트 생성, 병렬 처리, 통합)을 약속한다. 그러나 이 코드 조각은 이미 존재하는 execution_plan과 에이전트 출력 파일을 기반으로 결과를 읽고 누락 여부를 검사하며 FINAL_REPORT.md를 작성하는 'consolidation' 단계만 수행한다. mission.json 수정과 파일 입출력은 선언된 통합 목적과 관련된 범위 내이지만, 설명의 주된 가치 제안인 자동 멀티에이전트 구성/실행 기능을 구현하지 않는다. 따라서 코드의 실제 1차 목적은 설명보다 훨씬 좁고 materially different 하므로 mismatch로 판단한다.
설명은 이 스킬의 핵심 기능이 멀티에이전트 오케스트레이션 전체 흐름(분해, 생성, 실행, 통합)이라고 주장한다. 그러나 실제 코드 조각은 저장된 미션 메타데이터와 출력 파일 존재 여부를 확인해 진행률을 계산하고 로그를 출력하는 읽기 중심의 모니터링 도구다. 일부 문자열에 consolidate.py 안내가 나오지만 직접 통합을 실행하지 않으며, 에이전트를 만들거나 태스크를 분해하거나 병렬 작업을 관리하는 로직도 없다. 따라서 선언된 주된 목적과 실제 동작 사이에 중대한 불일치가 있다.
Yes, this is a mismatch. The declared description claims substantial multi-agent automation capabilities, but the supplied code chunk is only an empty test-package initializer with a comment. There is no functional code supporting the stated purpose. While this may be only a partial repository snippet, based on the supplied code alone the actual behavior does not match the declared functionality.
설명은 복잡한 태스크를 자동 분해하고 여러 전문 에이전트를 동적으로 생성하여 병렬 실행·통합하는 '오케스트레이션' 시스템을 주장한다. 그러나 제공된 코드 조각은 scripts/consolidate의 함수들에 대한 테스트 파일로, 이미 존재하는 출력 파일을 읽고, 누락/빈 결과를 검증하며, 텍스트 요약을 생성하는 동작만 확인한다. 즉 일부 '결과 통합' 측면은 간접적으로 관련이 있지만, 핵심으로 선언된 에이전트 생성, 태스크 분해, 병렬 오케스트레이션, 트리거 기반 실행 같은 주된 기능은 나타나지 않는다. 따라서 선언된 목적과 실제 코드의 주된 역할 사이에 중대한 불일치가 있다.
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.
try:
while True:
os.system('clear' if os.name == 'posix' else 'cls')
mission, plan = load_mission(mission_id)
mission_path = Path(mission["path"])
The description highlights autonomous decomposition, team formation, parallel execution, and result consolidation but does not warn users that their task contents may be redistributed across multiple agents or profiles. In this context, the omission increases the chance that sensitive inputs are shared more widely than the user realizes, especially because the skill explicitly supports temporary agents and other bot instances.
The example invocation uses a very broad natural-language trigger ("어벤저스 어셈블!") without stating activation boundaries, consent requirements, or exclusions. In a skill that orchestrates automatic task decomposition and multi-agent execution, ambiguous triggering can cause unintended activation on ordinary user phrasing, leading to unnecessary delegation, unintended data propagation to subagents, or autonomous report generation beyond user expectations.
The skill documents code-capable operations such as sessions spawning, inter-agent messaging, profile routing, shared memory, and file-writing behavior, but it does not declare any explicit tool scope or allowed-tools boundary. In an orchestration skill that can delegate work and potentially touch shell, environment, and files, missing permission constraints significantly increases the risk of overbroad execution, unintended delegation, and privilege misuse.
The natural-language instructions, examples, and usage guidance are presented entirely in Korean, but the document does not state that this is a Korea-specific skill or offer users a language option. Under the language/locale policy, forcing a specific language without opt-in can be a policy concern.
The trigger list includes broad natural-language phrases such as '멀티에이전트 자동화', '에이전트 팀 구성', and '자동 에이전트' that could match ordinary user requests and activate a high-impact orchestration skill unexpectedly. In this context, accidental activation is more dangerous because the skill is designed to delegate tasks, spawn agents, and potentially use powerful tools across profiles.
This JSON manifest uses Korean for the task and all subtask descriptions/expected outputs, which effectively constrains the skill to a specific language/locale. The file does not indicate any user opt-in, language selection, or region-specific justification, so it conflicts with the language/locale policy criteria.
The trigger phrase set includes broad, generic terms such as "에이전트 팀" and collaboration-oriented wording that could match ordinary user requests unrelated to this specific skill. In an orchestration skill that can automatically decompose tasks and spawn multiple agents, accidental invocation increases the chance of unexpected automation, excessive tool use, or unintended delegation of sensitive work.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
}
# 미션 파일 저장
with open(mission_path / "mission.json", "w") as f:
json.dump(mission, f, indent=2, ensure_ascii=False)
return mission
The manifest describes an all-in-one system that automatically breaks down complex tasks and dynamically creates/spawns specialist agents. In code, decompose_task is a stub that always returns an empty list, and the script only emits JSON command parameters for later execution rather than performing the orchestration it advertises.
The spawned agent prompt is written entirely in Korean and instructs the agent in that language, which can force a specific language/locale on downstream behavior. The file does not provide any user opt-in, fallback, or explanation that the skill is intentionally Korean-only.
The message sent to existing agents is always composed in Korean, which imposes a language choice without opt-in. This matches the language/locale policy concern because no alternative locale handling or explicit justification is present.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
})
# 계획 저장
with open(mission_path / "execution_plan.json", "w") as f:
json.dump(plan, f, indent=2, ensure_ascii=False)
return str(mission_path / "execution_plan.json")
The module description and later user-facing strings are written in Korean, indicating the skill is designed to communicate in a specific language. The file does not offer any opt-in or alternative locale handling, which matches the policy category for language/locale constraints in natural-language content.
The script ultimately writes to mission.json under a mission_path derived from mission metadata loaded from a workspace rooted in an environment-controlled base directory and a user-supplied mission ID. Because mission["path"] is trusted without canonicalization or containment checks, an attacker who can influence the workspace contents or mission metadata can redirect writes to arbitrary filesystem locations, causing unauthorized file overwrite. In a multi-agent orchestration skill that reads and writes many files automatically, this trust boundary issue is more dangerous because untrusted agent-produced state may be fed back into privileged file operations.
if updates:
mission.update(updates)
with open(mission_path / "mission.json", "w") as f:
json.dump(mission, f, indent=2, ensure_ascii=False)
The report output path is attacker-controllable through the --output argument, and the default path also depends on untrusted mission_path state. The script opens that path for writing without validation, enabling arbitrary file overwrite or clobbering if a caller supplies a sensitive path or if mission metadata points outside the intended workspace. In an automation skill intended to consolidate outputs, this is especially risky because operators may run it with elevated privileges over broad workspaces.
else:
output_path = mission_path / "FINAL_REPORT.md"
with open(output_path, "w") as f:
f.write(report)
# 상태 업데이트
The module docstring says the script performs agent spawn/dispatch execution based on the execution plan, and the CLI description also presents it as an execute command. In practice, the code generates OpenClaw command strings, logs the mission as started/executing, prints them for a human to run, and never actually invokes any agent-spawning API itself.
This code file contains natural-language strings that present the skill in Korean, starting with the module description at L004 and continuing in user-facing CLI help/output. The policy allows locale constraints only when the skill offers language choice or clearly documents and justifies the restriction, which is not present here.
The write target is ultimately derived from mission metadata loaded from a mission directory whose root comes from an environment-controlled workspace and user-supplied mission ID. Because mission_path is taken from mission["path"] without validation, a crafted mission file can redirect writes to arbitrary filesystem locations, causing file overwrite or corruption under the current user's privileges.
if updates:
mission.update(updates)
with open(mission_path / "mission.json", "w") as f:
json.dump(mission, f, indent=2, ensure_ascii=False)
The log file path is built from mission_path, which is attacker-influenced through environment/workspace selection and untrusted mission metadata. An attacker who can plant or modify mission.json can cause append operations to arbitrary files, enabling log injection, file clobbering, or pollution of sensitive user files.
"data": data or {}
}
with open(log_file, "a") as f:
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
No suspicious patterns detected.