Back to skill

Security audit

Skill Forge

Security checks for vulnerabilities and agentic risk

Overview

This skill is transparent about building and installing other skills, but its update and uninstall flows have safety gaps that could persist unsafe instructions or delete the wrong files.

Use this only in a controlled workspace until the update and uninstall flows are fixed. Prefer plan-only mode, review generated and evolved skill folders before approval, use a dedicated Telegram env file containing only Telegram values, avoid generic .env auto-discovery, and do not enable scheduled or Telegram-approved mutations unless you trust the local install manifest and feedback source.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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)

T01 · Skill Instruction Hijacking

Error
Location
scripts/evolve/propose_skill_update.py:157
Finding

Untrusted feedback is embedded into persistent Agent-loaded Skill instructions

Content
View full analysis

Vulnerability Details

File Location: scripts/evolve/propose_skill_update.py:88-93, 127-153, 157-194, 231-233
Vulnerability Type: Persistent instruction injection through feedback-derived Skill content
Risk Level: High

Vulnerable Code

python
def explicit_trigger_suggestions(entries: list[dict]) -> list[str]:
    triggers = []
    patterns = [
        r"(?:trigger|trigger phrase|触发词|触发语)[::]\s*([^。\n;;]+)",
        r"(?:when user says|用户说)[::]\s*([^。\n;;]+)",
    ]
    for entry in entries:
        text = "\n".join(str(entry.get(key) or "") for key in ["feedback", "expected", "task"])
        for pattern in patterns:
            for match in re.findall(pattern, text, flags=re.IGNORECASE):
                value = clean_trigger(match)
                if value and value not in triggers:
                    triggers.append(value)
    return triggers[:8]
python
def add_trigger_cues(skill_md: Path, triggers: list[str]) -> list[str]:
    if not triggers:
        return []
    content = skill_md.read_text(encoding="utf-8")
    existing = set(re.findall(r"(?m)^\s*-\s+`?([^`\n]+?)`?\s*$", content))
    to_add = [trigger for trigger in triggers if trigger not in existing]
    if not to_add:
        return []
    insertion = "\n".join(f"- `{trigger}`" for trigger in to_add)
    if "## Trigger Cues" in content:
        pattern = re.compile(
            r"(?ms)(## Trigger Cues.*?Use this skill when the user mentions:\n\n)(.*?)(\n## |\Z)"
        )
        new_content, replacements = pattern.subn(
            lambda match: match.group(1) + match.group(2).rstrip() + "\n" + insertion + match.group(3),
            content,
            count=1,
        )
        if replacements == 0:
            new_content = content.rstrip() + "\n" + insertion + "\n"
        content = new_content
    else:
        content += "\n\n## Trigger Cues\n\nUse this skill when the user mentions:\n\n" + insertion + "\n"
    skill_md.write_text(content, encoding="utf-8")
   
...[truncated 4801 chars]
Remediation
View remediation

Remediation Suggestions

  1. Do not place raw feedback in files that an Agent may load as instructions.
  2. Store feedback outside the Skill package in a dedicated data store with a strict separation between instructions and evidence.
  3. If feedback must accompany a candidate, serialize it as inert JSON and ensure the Agent-facing instructions explicitly prohibit treating its contents as commands.
  4. Escape Markdown metacharacters and normalize or reject newlines, headings, code blocks, links, role labels, and instruction-like directives.
  5. Add an instruction-injection scanner covering SKILL.md, all references, generated Agent metadata, and scripts before validation can pass.
  6. Require explicit human review of each feedback-derived textual change rather than approving only aggregate scores.
  7. Maintain an allowlist for trigger syntax and reject trigger values containing control language, tool commands, URLs, or role directives.
  8. Record provenance and trust level for every generated section so untrusted feedback cannot silently become authoritative Skill guidance.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/install/propose_skill_install.py:153
Finding

Approved uninstall can delete a manifest-substituted path outside the target root

Content
View full analysis

Vulnerability Details

File Location: scripts/install/propose_skill_install.py:153-166, 261-274
Vulnerability Type: Unvalidated destructive path loaded from a mutable manifest
Risk Level: High

Vulnerable Code

python
def uninstall_skill(skill_name: str, target_root: Path, restore_backup: bool) -> dict:
    with _ManifestLock(target_root):
        manifest = load_manifest(target_root)
        installs = manifest.setdefault("installs", {})
        record = installs.get(skill_name, {})
        target = Path(record.get("target", str(target_root / skill_name)))
        removed = target.exists() or target.is_symlink()
        if removed:
            remove_target(target)

        restored_backup = None
        backup = record.get("previous_backup")
        if restore_backup and backup:
            backup_path = Path(backup)
            if backup_path.exists() or backup_path.is_symlink():
                backup_path.rename(target)
                restored_backup = str(target)
python
if args.uninstall:
    skill_name = Path(args.skill_dir).name
    if args.apply:
        target = str(target_root / skill_name)
        ok, reason, claims = verify_token(
            args.approval_token,
            secret,
            expected={"skill": skill_name, "target": target, "method": args.method},
        )
        if not ok:
            return emit_blocked(
                f"approval token rejected: {reason}",
                {"claims": claims},
            )
        mode = claims.get("mode", "telegram")
        if mode == "dry-run" and not args.allow_dry_run_install:
            return emit_blocked(
                "dry-run approval cannot mutate state",
                {"claims": claims},
            )
        approved_by_label = "dry-run" if mode == "dry-run" else "telegram"
        approval_claims = claims
    if args.apply:
        plan = uninstall_skill(skill_name, target_root, args.restore_backup)

The destructive sink is:

python
de
...[truncated 2508 chars]
Remediation
View remediation

Remediation Suggestions

  1. Never trust the manifest to select the destructive uninstall target.
  2. Derive the target exclusively from the verified approval claims and the validated Skill name.
  3. Resolve the target and require it to be an immediate child of the resolved target_root.
  4. Reject any target equal to target_root, outside it, or containing unexpected path components.
  5. Compare the actual deletion target byte-for-byte with the path bound into the approval token.
  6. Validate symlink behavior before deletion and unlink only the intended symlink rather than following substituted paths.
  7. Apply equivalent containment and identity checks to previous_backup before restoration.
  8. Protect the manifest with restrictive permissions and validate its schema and ownership before use.
  9. Recheck target identity while holding the manifest lock immediately before deletion to reduce time-of-check/time-of-use risks.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/lib/telegram_config.py:6
Finding

Telegram configuration discovery imports unrelated secrets from generic environment files

Content
View full analysis

Vulnerability Details

File Location: scripts/lib/telegram_config.py:6-12, 25-49
Vulnerability Type: Excessive credential loading and process-environment contamination
Risk Level: Medium

Vulnerable Code

python
DEFAULT_ENV_FILES = [
    Path.home() / ".openclaw" / "telegram.env",
    Path.home() / ".openclaw" / "skill-forge.env",
    Path.home() / ".openclaw" / ".env",
    Path.home() / ".openclaw" / "workspace" / "telegram.env",
    Path.home() / ".openclaw" / "workspace" / ".env",
]
python
def load_env_file(path: Optional[str]) -> Optional[Path]:
    if not path:
        return None
    env_path = Path(path).expanduser()
    if not env_path.exists():
        return None
    for line in env_path.read_text(
        encoding="utf-8",
        errors="ignore",
    ).splitlines():
        stripped = line.strip()
        if not stripped or stripped.startswith("#") or "=" not in stripped:
            continue
        key, value = stripped.split("=", 1)
        os.environ.setdefault(
            key.strip(),
            value.strip().strip('"').strip("'"),
        )
    return env_path
python
def load_default_env_files(extra_env_file: str = "") -> list[str]:
    loaded = []
    explicit = load_env_file(extra_env_file)
    if explicit:
        loaded.append(str(explicit))
    for candidate in DEFAULT_ENV_FILES:
        loaded_path = load_env_file(str(candidate))
        if loaded_path:
            loaded.append(str(loaded_path))
    return loaded

Technical Analysis

The Telegram workflow only requires a bot token and a chat identifier, but configuration discovery reads multiple generic .env files and imports every parsed key into the global process environment.

Generic files such as ~/.openclaw/.env and ~/.openclaw/workspace/.env may contain unrelated database passwords, cloud credentials, API keys, signing keys, or service tokens. Loading all entries violates least privilege and makes those values available to ev ...[truncated 1586 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse only an explicit allowlist of Telegram variable names:
    • TELEGRAM_BOT_TOKEN
    • OPENCLAW_TELEGRAM_BOT_TOKEN
    • TELEGRAM_CHAT_ID
    • OPENCLAW_TELEGRAM_CHAT_ID
  2. Return configuration values directly instead of copying them into global os.environ.
  3. Remove generic .env files from automatic discovery and prefer a dedicated Telegram configuration file.
  4. Require explicit consent or an explicit path before reading any environment file.
  5. Pass a minimal environment dictionary to child processes rather than inheriting the complete process environment.
  6. Apply restrictive filesystem permissions to dedicated credential files and reject files with unsafe ownership or permissions.
  7. Avoid returning unnecessary configuration-path details in user-facing error output.
Vulnerability Patterns
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • 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
Findings (83)

Tainted flow: 'token' from os.getenv (line 189, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/install/telegram_approval.py (reported line 40)May include surrounding context.

python
def get_json(token: str, method: str, params: dict) -> dict:
    query = urllib.parse.urlencode(params)
    with urllib.request.urlopen(f"{api_url(token, method)}?{query}", timeout=35) as response:
        return json.loads(response.read().decode("utf-8"))

Tainted flow: 'request' from os.getenv (line 47, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/somnia/reporting.py (reported line 54)May include surrounding context.

python
method="POST",
    )
    try:
        with urllib.request.urlopen(request, timeout=30) as response:
            payload = json.loads(response.read().decode("utf-8"))
    except Exception as exc:
        return {"sent": False, "status": "send-error", "error": str(exc)}

Tp4

High
Category
MCP Tool Poisoning
Confidence
88% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Executing Telegram approval/install wrappers broadens both network and mutation capabilities beyond the declared purpose. The concern is not merely wrapper usage, but that operationally sensitive delegated behavior may escape top-level review if hidden behind generic commands.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.