Back to skill

Security audit

RLM Controller

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-built for long-document analysis, but it uses autonomous exec and session spawning while some advertised safety limits and prompt-isolation protections are not fully enforced.

Install only if you are comfortable with a skill that can run bundled helper scripts, write full input copies and prompts to disk, and spawn sub-agent sessions. Use it in a workspace you control, avoid sensitive inputs unless you trust the redaction limits, review generated toolcalls before execution, consider enabling disableModelInvocation for confirmation, and run cleanup carefully because CLEAN_RETENTION=0 deletes matching scratch files.

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

Warning
Location
scripts/rlm_auto.py:63
Finding
Untrusted slice content is not isolated from sub-agent instructions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/rlm_auto.py:63-73`; `scripts/rlm_emit_toolcalls.py:54-70` **Vulnerability Type**: Prompt injection caused by ineffective role separation **Risk Level**: Medium ### Vulnerable Code ```python # scripts/rlm_auto.py:63-73 for i, sl in enumerate(trimmed, 1): slice_text = text[sl["start"]:sl["end"]] goal_text = args.goal if args.redact: slice_text = redact_secrets(slice_text) goal_text = redact_secrets(goal_text) prompt_path = os.path.join(prompts_dir, f"subcall_{i:02d}.txt") with open(prompt_path, "w", encoding="utf-8") as f: f.write("Slice:\n") f.write(slice_text) f.write("\n\nGoal:\n") f.write(goal_text) ``` ```python # scripts/rlm_emit_toolcalls.py:54-70 sys_prompt = read_text(args.subcall_system) items = read_spawn(args.spawn) batches = {} for it in items: batches.setdefault(it['batch'], []).append(it) out = [] for batch_id in sorted(batches.keys()): batch_calls = [] for it in batches[batch_id]: user_prompt = read_text(it['prompt_file']) full_prompt = f"SYSTEM:\n{sys_prompt}\n\nUSER:\n{user_prompt}\n" batch_calls.append({ "tool": EMITTED_TOOL, "params": { "task": full_prompt, "label": f"rlm_subcall_b{batch_id}" } }) ``` ### Technical Analysis The project claims that instructions found inside analyzed input are treated only as data. However, the implementation copies untrusted slice content and the user-provided goal into a prompt file, then concatenates the supposed system and user messages into one `task` string. The `SYSTEM:` and `USER:` markers are plain text. They are not independently enforced message roles at the model API or tool boundary. Consequently, an instruction embedded in a document slice can compete with the intended sub-agent instructions. Secret redaction does not mitigate this issue because it onl ...[truncated 1577 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use the agent framework's native, separately enforced system and user message roles instead of placing textual `SYSTEM:` and `USER:` labels inside one task string. 2. Bundle a reviewed, mandatory sub-agent system prompt with the project rather than requiring an unspecified external prompt file. 3. Explicitly instruct sub-agents that document slices are untrusted data and that instructions contained in those slices must never be followed. 4. Place slice data in a well-defined structured envelope, such as a JSON field or strongly delimited block, while clarifying that the field contains content to analyze rather than instructions. 5. Keep the analysis objective outside the untrusted slice-data field. 6. Validate sub-agent responses against an expected schema before aggregation and reject output that contains unexpected tool requests or control instructions. 7. Add adversarial tests containing prompt-injection phrases, forged role markers, and requests to ignore prior instructions. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/rlm_auto.py:28
Finding
Documented hard limits can be overridden during prompt generation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/rlm_auto.py:28-55` **Vulnerability Type**: Improper input validation and resource-limit bypass **Risk Level**: Medium ### Vulnerable Code ```python p.add_argument('--max-subcalls', type=int, default=32) p.add_argument('--slice-max', type=int, default=16000) p.add_argument('--redact', dest='redact', action='store_true', default=True, help='Redact secrets from slice text in subcall prompts (default: enabled)') p.add_argument('--no-redact', dest='redact', action='store_false', help='Disable secret redaction in subcall prompts') args = p.parse_args() _validate_path(args.outdir) os.makedirs(args.outdir, exist_ok=True) plan = run_plan(args.ctx, args.goal) slices = plan.get("slices", []) # fallback: if no keyword hits, chunk the doc if not slices: text = read_text(args.ctx) step = args.slice_max slices = [{"start": i, "end": min(len(text), i+step), "kw": "chunk"} for i in range(0, len(text), step)] # trim to max subcalls and max slice length slices = slices[:args.max_subcalls] trimmed = [] for sl in slices: start, end = sl["start"], sl["end"] if end - start > args.slice_max: end = start + args.slice_max trimmed.append({"start": start, "end": end, "kw": sl.get("kw","")}) ``` ### Technical Analysis The security documentation describes 32 subcalls and 16,000 characters per slice as hard safeguards. In `rlm_auto.py`, however, these values are only command-line defaults. The program does not verify that: - `max_subcalls` is between 1 and 32. - `slice_max` is between 1 and 16,000. - The aggregate size of generated prompt artifacts remains bounded. An invocation can therefore provide values exceeding the documented limits. Excessive values can cause oversized or excessive prompt files to be generated before downstream scripts apply the separate 32-entry spawn-manifest limit. Invalid lower-bound values are also unsafe. In the fall ...[truncated 1324 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define immutable implementation limits, for example: ```python MAX_SUBCALLS = 32 MAX_SLICE_CHARS = 16000 if not 1 <= args.max_subcalls <= MAX_SUBCALLS: p.error(f"--max-subcalls must be between 1 and {MAX_SUBCALLS}") if not 1 <= args.slice_max <= MAX_SLICE_CHARS: p.error(f"--slice-max must be between 1 and {MAX_SLICE_CHARS}") ``` 2. Treat CLI parameters as requests within fixed bounds rather than replacements for security limits. 3. Cap the aggregate number of bytes written across all prompt artifacts. 4. Consider limiting the maximum accepted context-file size or process large contexts through bounded streaming. 5. Validate slice start and end values before using them. 6. Perform validation before reading the full context or creating output directories. 7. Add tests for zero, negative, boundary, and excessively large values. 8. Keep downstream limit checks as defense in depth, but do not rely on them to protect earlier processing stages. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/rlm_auto.py:36
Finding
Derived output paths can follow symlinks outside the workspace<![CDATA[ ## Vulnerability Details **File Location**: `scripts/rlm_auto.py:36-37, 59-60, 68-69, 85-86` **Vulnerability Type**: Symlink-based path-containment bypass and unsafe file creation **Risk Level**: Medium ### Vulnerable Code ```python _validate_path(args.outdir) os.makedirs(args.outdir, exist_ok=True) ``` ```python prompts_dir = os.path.join(args.outdir, "subcalls") os.makedirs(prompts_dir, exist_ok=True) prompt_files = [] for i, sl in enumerate(trimmed, 1): slice_text = text[sl["start"]:sl["end"]] goal_text = args.goal if args.redact: slice_text = redact_secrets(slice_text) goal_text = redact_secrets(goal_text) prompt_path = os.path.join(prompts_dir, f"subcall_{i:02d}.txt") with open(prompt_path, "w", encoding="utf-8") as f: f.write("Slice:\n") f.write(slice_text) f.write("\n\nGoal:\n") f.write(goal_text) prompt_files.append({"file": prompt_path, **sl}) ``` ```python out_path = os.path.join(args.outdir, "plan.json") with open(out_path, "w", encoding="utf-8") as f: json.dump(out, f, indent=2) ``` ### Technical Analysis The script validates only the caller-supplied parent directory. It does not validate the resolved paths of the derived `subcalls` directory, individual `subcall_*.txt` files, or `plan.json` immediately before opening them. Path containment is therefore subject to a time-of-check/time-of-use gap and symlink substitution. For example: - `outdir/subcalls` can be a symlink to a directory outside the working directory. - `outdir/plan.json` can be a symlink to an external file. - An attacker with concurrent workspace access may replace a validated path component after validation but before a write. Python's normal `open(..., "w")` follows symlinks and truncates an existing target. The derived writes therefore do not consistently receive the protection provided by `rlm_path.validate_path()`. ### Attack Path 1. A local attacker gains the ability to create or mod ...[truncated 1118 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate every final derived path immediately before opening or creating it: ```python prompts_dir = _validate_path(os.path.join(args.outdir, "subcalls")) prompt_path = _validate_path(os.path.join(prompts_dir, f"subcall_{i:02d}.txt")) out_path = _validate_path(os.path.join(args.outdir, "plan.json")) ``` 2. Explicitly reject symlinked output directories and destination files with `os.path.islink()` or descriptor-based checks. 3. On supported platforms, create files with `os.open()` using `O_NOFOLLOW`, `O_CREAT`, and an appropriate exclusivity or truncation policy, then wrap the descriptor with `os.fdopen()`. 4. Create a fresh, unpredictable run directory with restrictive permissions rather than reusing an attacker-modifiable directory. 5. Open and verify the parent directory through a directory file descriptor and use `openat`-style operations to reduce time-of-check/time-of-use races. 6. Avoid truncating existing files unless explicitly required. Prefer atomic temporary-file creation followed by a validated rename. 7. Extend path-validation tests to cover symlinked `subcalls` directories, symlinked `plan.json` files, and concurrent path replacement. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (42)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This finding highlights undeclared cleanup and file deletion behavior exposed through `scripts/cleanup.sh`, including environment-controlled retention and ignore settings. Hidden destructive filesystem operations are dangerous because operators may invoke the skill expecting analysis only, while it can also purge artifacts or potentially remove unintended files if path handling or retention logic is flawed.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
These scripts:
- Accept only structured CLI arguments (argparse)
- Produce only JSON or plain-text output to stdout
- Never call `eval()`, `exec()`, `subprocess.Popen(shell=True)`, or equivalent
- Never interpret model output as code or commands
- Never make network requests
Confidence
80% 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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
These scripts:
- Accept only structured CLI arguments (argparse)
- Produce only JSON or plain-text output to stdout
- Never call `eval()`, `exec()`, `subprocess.Popen(shell=True)`, or equivalent
- Never interpret model output as code or commands
- Never make network requests
Confidence
80% 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).

Credential Access

High
Category
Privilege Escalation
Content
cmd = [
            sys.executable,
            os.path.join(SCRIPTS_DIR, 'rlm_ctx.py'),
            'store', '--infile', '../../../etc/passwd',
            '--ctx-dir', self.tmpdir,
        ]
        result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.tmpdir)
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
cmd = [
            sys.executable,
            os.path.join(SCRIPTS_DIR, 'rlm_ctx.py'),
            'store', '--infile', '../../../etc/passwd',
            '--ctx-dir', self.tmpdir,
        ]
        result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.tmpdir)
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
cmd = [
            sys.executable,
            os.path.join(SCRIPTS_DIR, 'rlm_ctx.py'),
            'store', '--infile', '../../../etc/passwd',
            '--ctx-dir', self.tmpdir,
        ]
        result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.tmpdir)
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill advertises use of powerful capabilities (`read`, `write`, `exec`, `sessions_spawn`) but does not declare an explicit tool scope such as `permissions` or `allowed-tools`. That creates a policy gap where the runtime may grant broader access than intended, increasing the blast radius if prompts, helper scripts, or spawned sessions are abused.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Content
## Tooling
- Uses OpenClaw tools: `read`, `write`, `exec`, `sessions_spawn`
- `exec` is used **only** to invoke the safelisted helper scripts bundled in `scripts/`
- Does **not** execute arbitrary code from model output
- All emitted toolcalls are validated against an explicit safelist before output

## Autonomous Invocation
Confidence
88% confidence
Finding
The skill explicitly uses `exec` and `sessions_spawn`, both of which materially increase attack surface, yet the only stated guard is a textual safelist claim in documentation. Without enforceable tool scoping and independently verified argument/path constraints, a compromised helper script, prompt-manipulated workflow, or unsafe spawned session could lead to command execution, file modification, or lateral expansion of model actions.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The documentation provides a destructive cleanup command that can delete all retained files by setting CLEAN_RETENTION=0, but it does not include warnings, confirmation steps, scope limitations, or examples showing how to verify the target directories before execution. In a controller skill that operates over workspace scratch data and generated run artifacts, this increases the chance of accidental data loss by operators or downstream automation that follows the documented flow verbatim.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes a controller for treating inputs as external context, slicing/searching them, and spawning bounded recursive subcalls for analysis. This script instead deletes files from scratch and log directories, which is operational workspace maintenance rather than long-context control behavior.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_plan(ctx, goal):
    cmd = ["python3", os.path.join(os.path.dirname(__file__), "rlm_plan.py"),
           "--ctx", ctx, "--goal", goal]
    out = subprocess.check_output(cmd, text=True)
    return json.loads(out)

def read_text(path):
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.