Back to skill

Security audit

Research Mode

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent long-running research tool, but it gives agents broad background execution, URL capture, and arbitrary package-install powers that users should review carefully.

Install only if you trust the operator workflow and will run it in an environment where background cron jobs, task-local files, URL snapshots, and package installs are acceptable. Keep sensitive credentials out of the runtime environment, require human approval for new packages, and avoid using URL capture against untrusted or attacker-controlled hosts until the DNS-rebinding gap is fixed.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/research_mode_control_commands.py:138
Finding

DNS Rebinding Can Bypass URL Fetch Restrictions and Enable SSRF

Content
View full analysis

Vulnerability Details

File Location: scripts/research_mode_control_commands.py:138-190
Vulnerability Type: Server-Side Request Forgery through DNS time-of-check/time-of-use inconsistency
Risk Level: High

Vulnerable Code

python
def _validate_fetchable_url(url: str) -> None:
    parsed = urlparse(url)
    if parsed.scheme not in {"http", "https"}:
        raise ValidationError(
            "attach-url-as-md only supports http:// and https:// URLs"
        )
    host = (parsed.hostname or "").strip().rstrip(".")
    if not host:
        raise ValidationError("attach-url-as-md requires a URL host")
    lowered = host.lower()
    if lowered == "localhost" or lowered.endswith(".localhost"):
        raise ValidationError(f"Blocked local or private host in URL: {host}")
    try:
        ipaddress.ip_address(host)
    except ValueError:
        port = parsed.port or (443 if parsed.scheme == "https" else 80)
        try:
            resolved = socket.getaddrinfo(host, port, type=socket.SOCK_STREAM)
        except OSError as exc:
            raise ValidationError(
                f"Failed to resolve URL host: {host} ({exc})"
            ) from exc
        for item in resolved:
            sockaddr = item[4]
            ip_text = str(sockaddr[0])
            if _is_blocked_url_ip(ip_text):
                raise ValidationError(
                    f"Blocked local or private host in URL: {host}"
                )
    else:
        if _is_blocked_url_ip(host):
            raise ValidationError(
                f"Blocked local or private host in URL: {host}"
            )


class _ValidatedRedirectHandler(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        _validate_fetchable_url(str(newurl))
        return super().redirect_request(req, fp, code, msg, headers, newurl)


def _fetch_url_as_m
...[truncated 3642 chars]
Remediation
View remediation

Remediation Suggestions

  1. Resolve each hostname once and retain only addresses that pass the network policy.
  2. Connect directly to a selected validated IP address rather than allowing the HTTP library to resolve the hostname again.
  3. Preserve the original hostname for the HTTP Host header and TLS Server Name Indication while connecting to the validated IP.
  4. Verify the connected socket's peer address before transmitting or accepting response data. Reject any peer that differs from the approved address set.
  5. Repeat the resolve, validate, connect, and peer-verification procedure for every redirect.
  6. Disable environment-derived proxies unless explicitly trusted. A proxy can otherwise change the effective network path and invalidate assumptions made by local DNS checks.
  7. Enforce network-level egress restrictions that block loopback, private, link-local, multicast, reserved, and cloud metadata ranges. Application validation should not be the sole SSRF control.
  8. Add regression tests using a connector whose validation lookup and connection lookup return different addresses. The test should prove that no request reaches the internal fixture.
  9. Apply response byte limits while streaming instead of reading the complete body before applying max_chars.
  10. Consider an explicit destination-host allowlist for automated or unattended research tasks.

T08 · Insecure Dependencies

Error
Location
scripts/research_mode_runtime.py:308
Finding

Arbitrary Unpinned Python Package Installation Enables Supply-Chain Code Execution

Content
View full analysis

Vulnerability Details

File Location: scripts/research_mode_runtime.py:308-348
Related Interface: scripts/research_mode.py:585-604
Vulnerability Type: Unrestricted dependency installation from untrusted package sources
Risk Level: High

Vulnerable Code

The command-line interface accepts arbitrary package specifications:

python
prepare_runtime = subparsers.add_parser(
    "prepare-runtime",
    help="Create a task-local workspace and isolated Python runtime",
    description="Prepare workspace/ plus .runtime/venv for heavier coding, analytics, exports, and package installs without polluting the main environment.",
    parents=[root_parent],
)
prepare_runtime.add_argument("--id", help="Research id")
prepare_runtime.add_argument("--path", help="Task directory or state.json path")
prepare_runtime.add_argument(
    "--python",
    default=None,
    help="Base Python interpreter/version hint for venv creation (passed to uv when available)",
)
prepare_runtime.add_argument(
    "--package",
    action="append",
    default=[],
    help="Extra package to install into the task-local venv (repeatable)",
)
prepare_runtime.add_argument(
    "--recreate",
    action="store_true",
    help="Recreate the task-local venv from scratch before use",
)
prepare_runtime.set_defaults(func=prepare_task_runtime)

The supplied values are passed to pip or uv without pinning, hash validation, an allowlist, or source restrictions:

python
packages_requested = [
    pkg.strip() for pkg in (args.package or []) if pkg.strip()
]
if getattr(args, "recreate", False) and task.venv_dir.exists():
    shutil.rmtree(task.venv_dir)

uv_path = shutil.which("uv")
tool = "uv" if uv_path else "venv"
python_bin = venv_python_path(task)
activate_path = venv_activate_path(task)
venv_created = False
env = os.environ.copy()
env.setdefault("UV_CACHE_DIR", str(tas
...[truncated 4575 chars]
Remediation
View remediation

Remediation Suggestions

  1. Introduce an explicit allowlist of approved packages and supported versions.
  2. Require exact version pins and verify package artifacts against committed hashes.
  3. Maintain a reviewed lockfile for standard analysis dependencies.
  4. Reject direct URL, VCS, editable, local-path, alternate-index, and installer-option syntax unless a human grants a documented exception.
  5. Configure a trusted internal package mirror or explicitly approved package index rather than inheriting arbitrary installer configuration.
  6. Prefer verified binary wheels and disable source builds where practical.
  7. Require explicit human approval before an unattended worker installs a package that is not already approved.
  8. Run installation in a sandbox or container with:
    • Access limited to the task directory.
    • No access to user credentials or unrelated home-directory files.
    • Minimal environment variables.
    • Blocked or tightly restricted network egress.
    • No elevated operating-system permissions.
  9. Separate dependency resolution and download from execution. Inspect provenance, signatures, hashes, maintainers, and release history before installation.
  10. Record the resolved package name, version, source index, artifact hash, and approval decision in runtime metadata.
  11. Add policy tests proving that unpinned names, typo-like packages, direct URLs, VCS requirements, local paths, and unapproved indexes are rejected.
  12. If arbitrary packages must remain supported, clearly classify the operation as privileged and require an interactive confirmation that identifies the exact source and resulting host-level risk.
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 (140)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description describes an orchestration skill for extended background research runs. The supplied code does not implement such a system. Instead, it performs a narrowly scoped finalization check on a predetermined filesystem location, validating package contents and an Excel workbook, scanning for potential private data markers, and emitting JSON review/result files. While the output JSON references research completion and findings, those are static summaries written by the script rather than evidence of durable, resumable research execution. This is a materially different primary purpose and capability set from the declared long-running research skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is for an orchestration skill that manages long-running background research with persistence and lifecycle controls. The code does none of that. Instead, it is a one-shot packaging script for a predefined research artifact: it contains hardcoded tool metadata and scoring weights, reads local JSONL files, creates an XLSX workbook and markdown documents, validates the workbook, and emits a generation summary. While it produces a final report-like output, that is only a small overlap; the core behavior is document synthesis for a specific analysis package, not durable research execution infrastructure.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description presents a general-purpose long-running research skill for OpenClaw. The supplied code does not implement any of those core behaviors. It does not schedule or manage iterations, maintain resumable state, perform research, collect findings over time, or generate a final research report from ongoing work. Instead, it is narrowly focused on validating a preexisting package in a fixed directory: checking required filenames, inspecting workbook sheets/tables/formulas/autofilters, scanning for disallowed strings, and emitting a JSON pass/fail report. This is a materially different primary purpose, so the description does not accurately represent the code.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description promises a durable research worker for OpenClaw that can run for hours or days with isolated iterations, persistent state, bounded execution, milestone updates, and lifecycle controls. The supplied code does none of that. It simply writes a fixed set of Markdown documentation files to disk and scans them for predefined regex patterns indicating private/internal content, then emits a JSON report. While the generated documents discuss research workflows and safety boundaries, the code itself is not implementing a long-running research system. This is a materially different primary purpose and lacks the core declared capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description promises a durable background research capability with lifecycle management and iterative execution over hours or days. The supplied code does not implement any of that. Instead, it validates an already-produced research package in a fixed local directory by checking required files, scanning for private-data markers, verifying textual coverage requirements, and confirming inclusion of expected URLs. This is a materially different primary purpose and behavior from the declared skill, so it should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description says the skill performs durable background research with persistence, scheduling, milestone tracking, and final reporting. The supplied code does not implement any research workflow or long-running task orchestration. Instead, it is a development/CI-style verification script for the skill itself, invoking compilers, linters, doc checks, smoke tests, type checkers, and unit/self tests. This is a materially different primary purpose and introduces undeclared capabilities related to code validation rather than user-facing research execution.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description presents the skill as an operational long-running research system. However, the supplied code chunk is not implementing research execution, cron orchestration, task lifecycle management, persistence behavior, milestone updates, or final report generation. Instead, it is a repository quality-assurance script focused on documentation consistency and example/schema validation. This is a materially different primary purpose, so the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description claims the skill performs durable background research with persistent iterative execution and milestone-driven reporting for user tasks. The code shown does not implement that worker capability. Instead, it is a test harness that calls research_mode.py as a subprocess, fabricates expected result payloads for each phase, validates phase/status transitions, and confirms the review/approval release path. While the tested system relates to Research Mode, this chunk's primary purpose is release smoke testing of the lifecycle, not conducting long-running research. That is a material description/behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The declared description presents a full durable research execution framework for long-running background work. The supplied code chunk does not implement that orchestration. Instead, it provides helper functions for checking whether accumulated research is sufficient, building validation guidance, mapping adequacy statuses to phases, and suggesting operator next actions. While this could be a supporting component within a larger long-running research system, this chunk’s actual purpose is adequacy review and routing, not durable execution, cron-based iteration, persistence/lifecycle management, or report production. Therefore the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The description portrays an execution/orchestration skill for durable background research. This code chunk instead focuses on end-of-task finalization: building contracts and surfaces from state, validating required finalization fields, inspecting candidate artifacts in the task workspace, checking deliverable format consistency, parsing markdown and XLSX/package contents, and generating operator next-action guidance for review/rework. While related to a broader research workflow, its primary purpose is materially different from 'run durable long-running research.' The code also exercises undeclared capabilities around filesystem traversal and artifact content inspection.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description promises a background research execution system with durability, bounded iterations, persistent state, and lifecycle controls. The supplied code does not implement any of those behaviors. Instead, it only provides static mappings and utility functions for legacy deliverable kinds and expected artifact formats. This is a materially different primary purpose, so the description does not accurately represent the code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description is about orchestrating long-running durable research workflows with persistence, cron-based execution, lifecycle controls, and milestone reporting. This code does not implement any of those core behaviors. Instead, it is a narrow utility module for preparing and adapting already-produced content for delivery across communication channels. Its primary purpose is materially different from the declared purpose, and the delivery/notification capabilities are undeclared in the description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description outlines a substantial background research system with durable execution and stateful workflow features. The actual code chunk only defines a pytest fixture in a self-test file that maps root to tmp_path. This is unrelated test scaffolding, not an implementation of the described skill. Therefore the code's primary purpose materially differs from the declared purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description says this skill runs durable long-running research workflows in OpenClaw. However, the actual code does not implement any research execution capability at all. It is a test file focused on approval integrity gates in a task/review system. Its primary behavior is invoking CLI commands like create, begin, finish, and approve to verify that approval requires a valid artifact, rejects missing or external artifacts, and records review history correctly. This is materially different from the declared purpose and introduces an undeclared capability area: testing approval/artifact validation logic rather than performing long-running research.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a production skill for conducting durable long-running research workflows. The supplied code, however, is a test file (scripts/selftest/test_budget.py) that validates budget-related mechanics of such a system. It does not itself perform research, orchestrate long-running cron execution, accumulate findings over time as a user-facing capability, or expose pause/resume/stop controls. Instead, it runs self-tests against commands like create/begin/finish/summary/draft-report and checks source/runtime budget handling and state transitions. While budget enforcement is one supporting aspect of the declared skill, this code chunk’s actual purpose is materially different: testing that feature, not implementing or operating the broader research skill.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents an operational skill that runs durable background research workflows in OpenClaw. The supplied code does not implement such a workflow; instead, it contains automated tests for several CLI commands. Those tests validate command behavior around job binding, unscheduling, formatting output for delivery channels, and dry-run semantics. While some tested behaviors loosely relate to persistent state or cron scheduling, the primary purpose and actual functionality of the code chunk are materially different from the declared purpose. Therefore this is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description presents an end-user research-running capability, but the actual code chunk is a test file focused on concurrency regressions in task lifecycle operations. It does not itself conduct research, manage milestone updates for users, or implement pause/resume/stop flows as its primary purpose. Instead, it verifies that begin/finish operations serialize correctly and that queue contention behaves safely. This is a materially different purpose from the declared skill behavior, so it should be flagged as a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents an operational skill for conducting durable, long-running background research with lifecycle management and reporting. The supplied code does not implement or invoke research execution, cron iteration management, bounded runs, pause/resume/stop controls, or source accumulation. Instead, it is a test file focused on validating consistency warnings and guidance in an existing research-task system by creating tasks, mutating state.json, and asserting expected warning output in JSON/text/playbook forms. That is a materially different primary purpose from the declared skill behavior, so this is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The supplied code does not implement a long-running research skill. It is a test file focused on contract-driven validation: reading local Python files, asserting certain identifiers are absent, and checking specific helper functions return guarded outputs. Its primary purpose is QA/testing of research_mode components, not executing background research jobs or managing durable research state. This is a material mismatch in purpose and behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description says this skill performs durable long-running background research orchestration. The code shown does not implement or invoke long-running research execution, cron iteration management, milestone reporting, pause/resume/stop lifecycle control, or final report synthesis as its primary behavior. Instead, it is a test module focused on corpus attachment/import behavior and URL safety validation. While some referenced commands belong to a research-mode system, this specific code chunk is materially different in purpose and capability from the declared description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This code chunk does not implement or primarily support long-running background research execution. Instead, it is a test suite for delivery/finalization mechanics after research work is done. While it references research tasks and lifecycle phases, its actual purpose is validating output artifacts, delivery manifests, review gating, approval defaults, and file safety. Core declared behaviors like isolated cron iterations, long-duration continuation, pause/resume/stop control, milestone updates, and accumulation of findings over time are not what this code chunk is doing. The mismatch is therefore material.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description presents an operational research skill for long-running background work with persistence, cron-style execution, and lifecycle controls. The supplied code does not implement any of those behaviors. It is exclusively test code for documentation and release-smoke validation. Its primary purpose is QA/verification of scripts and docs, not conducting research, maintaining state over time, or producing research reports. This is a clear material mismatch between declared purpose and actual behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents an operational research skill that runs durable long-running background research workflows. The supplied code does not implement that functionality; it is a test file focused on validating failure modes and edge cases of an existing system. While the tested commands relate to a research-task lifecycle, this chunk's primary purpose is QA/self-testing, not executing or orchestrating long-running research. That is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description says the skill runs durable long-running research workflows. The supplied code does not implement or invoke research logic as its primary function; instead, it is a self-test file focused on validating health and reconcile diagnostics for task state. While the tests touch concepts related to persistent state and long-running runs, they are strictly checking correctness of diagnostic commands and read-only behavior, including stale lock handling, pending result validation, manual review conditions, and recommended recovery actions. This is a materially different primary purpose from the declared capability, so the description does not accurately represent the code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The description presents an operational skill for conducting durable, long-running background research. However, the provided code chunk is not such an implementation; it is a unit test module. Its primary purpose is to verify behavior of helper functions related to research lifecycle metadata, scoring, validation, and user-facing status text. While these helpers are conceptually adjacent to a long-running research system, this chunk does not itself perform the declared capability of running ongoing research jobs, managing cron-like iterations, persisting/resuming tasks, or producing final reports. Therefore the code chunk does not accurately represent the declared purpose.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.