Back to skill

Security audit

Gateway Guardian

Security checks for vulnerabilities and agentic risk

Overview

This skill has a legitimate gateway-protection purpose, but it installs persistent services and has unsafe install/configuration paths that could run unintended commands.

Review this carefully before installing. Prefer a version that uses the bundled scripts only, pins or verifies any remote downloads, stores config in a non-executable format, validates notification IDs and bot names strictly, and clearly explains the persistent systemd services it will create.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:99
Finding
Shell Command Injection Through Unsafely Generated guardian.conf<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 99-133; execution sink in `config-lib.sh`, lines 20-21 **Vulnerability Type**: Shell command injection through untrusted configuration values **Risk Level**: High ### Vulnerable Code ```bash Ask the user: "What name should I use for myself in team notifications? (e.g. Claw, MyBot, OpenClaw — press Enter to skip and use the default 'OpenClaw')" Record as `BOT_NAME`. If the user skips, use `OpenClaw`. ``` ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/gateway-guardian" cat > "$SKILL_DIR/guardian.conf" << GUARDIANCONF # Auto-generated by gateway-guardian installer. Do not upload to GitHub. # Fallback notification target (used when dynamic session detection fails) FALLBACK_CHANNEL={FALLBACK_CHANNEL} FALLBACK_TARGET={FALLBACK_TARGET} # Notification language: zh (Chinese) | en (English) LOCALE={LOCALE} # Bot display name used in staff/team notifications BOT_NAME={BOT_NAME} # Team group/channel notification (optional) # Leave empty to disable. Supported formats: # Feishu: oc_xxx # Telegram: -100xxxxxxxxxx (supergroup/channel numeric id) # Discord: 123456789012345678 (channel id, digits only) # Only effective if the channel is configured and running in OpenClaw. STAFF_GROUP_CHAT_ID= GUARDIANCONF ``` The generated file is subsequently loaded as executable shell code: ```bash _GUARDIAN_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" [ -f "$_GUARDIAN_LIB_DIR/guardian.conf" ] && source "$_GUARDIAN_LIB_DIR/guardian.conf" ``` ### Technical Analysis The installer instructs the Agent to insert user-controlled `BOT_NAME` and conversation-derived notification values directly into an unquoted heredoc. An unquoted heredoc performs command substitution, backtick substitution, and parameter expansion while it is being processed. For example, if a value is inserted as: ```bash BOT_NAME=$(touch /tmp/gateway-guardian-injection) ``` the command substitution can execute immediate ...[truncated 1744 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not store untrusted values in a file that is loaded with `source`. Use JSON, TOML, or another non-executable format and parse it with a strict parser. 2. Generate configuration with a quoted heredoc so that the shell does not expand its body: ```bash cat > "$SKILL_DIR/guardian.conf" <<'GUARDIANCONF' ... GUARDIANCONF ``` 3. Pass values separately rather than replacing placeholders inside executable shell text. 4. If shell configuration is unavoidable, serialize each value with `printf '%q'` before writing it. 5. Enforce strict allowlists: - `FALLBACK_CHANNEL`: one of explicitly supported channel names. - `LOCALE`: exactly `zh` or `en`. - Notification IDs: channel-specific anchored regular expressions. - `BOT_NAME`: a conservative length and character allowlist. 6. Reject newlines, control characters, backticks, dollar signs, semicolons, shell redirection characters, and command-substitution syntax. 7. Create the file with restrictive permissions, such as mode `0600`. 8. Add tests using values containing `$(...)`, backticks, quotes, newlines, semicolons, backslashes, and redirection operators. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:258
Finding
Command and Configuration Injection in Team Group Update Flow<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 258-271; execution sink in `config-lib.sh`, lines 20-21 **Vulnerability Type**: Unsafe interpolation into a sed command and executable configuration **Risk Level**: High ### Vulnerable Code ```bash ## Set Team Group (AI-executed) When the user sends a message matching `设置通知群: <id>` or `set guardian group: <id>`: 1. Extract the group ID from the message 2. Determine the channel based on ID format: - Starts with `oc_` → feishu - Starts with `-100` → telegram - Pure digits → discord 3. Update `guardian.conf`: ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/gateway-guardian" sed -i "s|^STAFF_GROUP_CHAT_ID=.*|STAFF_GROUP_CHAT_ID={extracted_id}|" "$SKILL_DIR/guardian.conf" ``` ``` The modified file is subsequently executed as shell configuration: ```bash _GUARDIAN_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" [ -f "$_GUARDIAN_LIB_DIR/guardian.conf" ] && source "$_GUARDIAN_LIB_DIR/guardian.conf" ``` ### Technical Analysis The group identifier is extracted from a user message and interpolated directly into a double-quoted `sed` command. The instructions describe how to infer a channel from common identifier prefixes, but they do not explicitly require rejecting values that contain additional characters or malformed content. This creates two related injection surfaces: 1. Shell metacharacters introduced when the placeholder is replaced can alter the generated shell command. 2. `sed` replacement metacharacters, including the delimiter, backslashes, and `&`, can change the replacement behavior or inject additional content into `guardian.conf`. Because `guardian.conf` is later loaded with `source`, any injected shell statement becomes executable code. Newline injection is particularly dangerous because it can append an independent command beneath the `STAFF_GROUP_CHAT_ID` assignment. ### Attack Path 1. An attacker sends a crafted `set guardian group:` message containi ...[truncated 1085 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply strict, fully anchored validation before any update: - Feishu: `^oc_[A-Za-z0-9_-]+$` - Telegram: `^-100[0-9]+$` - Discord: `^[0-9]+$` 2. Enforce a reasonable maximum identifier length. 3. Reject all values containing whitespace, newlines, control characters, shell metacharacters, or unexpected delimiters. 4. Do not interpolate user input into a `sed` expression. 5. Prefer rewriting a structured, non-executable configuration file using a parser. 6. If retaining shell configuration, serialize the value with `printf '%q'` and write a complete replacement file atomically rather than editing it with interpolated `sed`. 7. Stop using `source` for configuration loading. 8. Write changes to a temporary file in the same protected directory, validate the completed configuration, set mode `0600`, and atomically rename it into place. ]]>

T03 · Remote Payload Retrieval and Execution

Warning
Location
SKILL.md:87
Finding
Mutable Remote Scripts Are Downloaded and Persistently Executed Without Integrity Verification<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 87-94; persistent execution registration at lines 146-196 **Vulnerability Type**: Unverified remote payload retrieval and execution **Risk Level**: Medium ### Vulnerable Code ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/gateway-guardian" mkdir -p "$SKILL_DIR" BASE_URL="https://raw.githubusercontent.com/Dios-Man/gateway-guardian/main" for f in config-lib.sh config-watcher.sh gateway-recovery.sh pre-stop.sh; do # Skip if file already present (e.g. installed via clawhub install) [ -f "$SKILL_DIR/$f" ] && continue curl -fsSL "$BASE_URL/$f" -o "$SKILL_DIR/$f" done ``` The downloaded files are then registered for persistent execution: ```bash cat > ~/.config/systemd/user/openclaw-config-watcher.service << EOF [Unit] Description=OpenClaw Gateway Guardian - File Watcher After=openclaw-gateway.service [Service] Type=simple ExecStart=/bin/bash $SKILL_DIR/config-watcher.sh Restart=always RestartSec=3 [Install] WantedBy=default.target EOF ``` ```bash cat > ~/.config/systemd/user/openclaw-recovery.service << EOF [Unit] Description=OpenClaw Gateway Guardian - Crash Recovery After=network.target [Service] Type=oneshot ExecStart=/bin/bash $SKILL_DIR/gateway-recovery.sh EOF ``` ```bash systemctl --user daemon-reload systemctl --user enable openclaw-config-watcher.service systemctl --user start openclaw-config-watcher.service ``` ### Technical Analysis The installation procedure downloads executable shell scripts from the mutable `main` branch. It does not pin an immutable commit, verify a cryptographic checksum, validate a release signature, or compare the downloaded files against the reviewed package. Therefore, the code that is ultimately executed can differ from the code reviewed during this audit. Compromise of the upstream repository, maintainer account, release process, or content-delivery path could replace any downloaded script with arbitrary code. Files are downloaded ...[truncated 1764 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Install the scripts bundled with the reviewed Skill package instead of retrieving replacements from the network. 2. If remote retrieval is required, pin the URL to an immutable commit hash rather than `main`. 3. Publish and verify SHA-256 hashes for every downloaded file. 4. Prefer signed release artifacts and verify the signature against a pinned maintainer key. 5. Download all files into a newly created staging directory with restrictive permissions. 6. Verify that every expected file is present and passes integrity checks before installation. 7. Install the verified set atomically so mixed versions cannot result from partial failures. 8. Fail closed on any download or verification error instead of continuing with a partial installation. 9. Record the exact installed commit and hashes to support later auditing and reproducibility. 10. Apply systemd hardening appropriate to the service, including restrictive filesystem access and privilege controls, to reduce the impact of a compromised payload. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (41)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```bash
touch ~/.openclaw/.guardian-maintenance   # pause monitoring
npm install -g openclaw@latest            # upgrade
rm ~/.openclaw/.guardian-maintenance      # resume → upgrade notification sent automatically
```

---
Confidence
85% 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
```bash
systemctl --user stop openclaw-config-watcher.service
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
Confidence
85% 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
```bash
systemctl --user stop openclaw-config-watcher.service
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
Confidence
85% 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
```bash
systemctl --user stop openclaw-config-watcher.service
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
Confidence
85% 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
systemctl --user stop openclaw-config-watcher.service
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
systemctl --user reset-failed openclaw-gateway.service 2>/dev/null
Confidence
85% 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
systemctl --user stop openclaw-config-watcher.service
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
systemctl --user reset-failed openclaw-gateway.service 2>/dev/null
Confidence
85% 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
systemctl --user stop openclaw-config-watcher.service
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
systemctl --user reset-failed openclaw-gateway.service 2>/dev/null
Confidence
85% 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
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
systemctl --user reset-failed openclaw-gateway.service 2>/dev/null
```
Confidence
85% 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
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
systemctl --user reset-failed openclaw-gateway.service 2>/dev/null
```
Confidence
85% 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
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
systemctl --user reset-failed openclaw-gateway.service 2>/dev/null
```
Confidence
85% 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
Config backups in `~/.openclaw/config-backups/` are kept after uninstall. To delete them:

```bash
rm -rf ~/.openclaw/config-backups/
```

---
Confidence
90% 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
Config backups in `~/.openclaw/config-backups/` are kept after uninstall. To delete them:

```bash
rm -rf ~/.openclaw/config-backups/
```

---
Confidence
90% 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
Config backups in `~/.openclaw/config-backups/` are kept after uninstall. To delete them:

```bash
rm -rf ~/.openclaw/config-backups/
```

---
Confidence
90% 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
Config backups in `~/.openclaw/config-backups/` are kept after uninstall. To delete them:

```bash
rm -rf ~/.openclaw/config-backups/
```

---
Confidence
90% 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
Config backups in `~/.openclaw/config-backups/` are kept after uninstall. To delete them:

```bash
rm -rf ~/.openclaw/config-backups/
```

---
Confidence
90% 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
Config backups in `~/.openclaw/config-backups/` are kept after uninstall. To delete them:

```bash
rm -rf ~/.openclaw/config-backups/
```

---
Confidence
90% 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).

Chaining Abuse

High
Category
Tool Misuse
Content
else
        cp "$CONFIG" "$tmp" 2>/dev/null || { echo "cannot read config file"; return 1; }
        if ! cp "$file" "$CONFIG" 2>/dev/null; then
            cp "$tmp" "$CONFIG"; rm -f "$tmp"
            echo "cannot copy file to config"; return 1
        fi
        result=$(timeout 30 openclaw config validate 2>&1)
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Chaining Abuse

High
Category
Tool Misuse
Content
fi
        result=$(timeout 30 openclaw config validate 2>&1)
        exit_code=$?
        cp "$tmp" "$CONFIG" && rm -f "$tmp"
    fi

    if [ $exit_code -ne 0 ] || echo "$result" | grep -qi "error\|invalid\|failed"; then
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
count=$(ls "$TIMESTAMP_DIR/" | wc -l)
    if [ "$count" -gt "$MAX_BACKUPS" ]; then
        ls -t "$TIMESTAMP_DIR/" | tail -n +$((MAX_BACKUPS + 1)) | \
            while IFS= read -r f; do rm -f "$TIMESTAMP_DIR/$f"; done
    fi
    log "💾 Backup saved: $(basename "$bak")"
}
Confidence
95% 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).

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **SKILL.md: guardian.conf placeholder resolution** — added explicit table showing how to
  resolve `FALLBACK_CHANNEL` and `FALLBACK_TARGET` from conversation context before writing
  the conf file; Step 4 now clearly states placeholders must be substituted before running
- **inotify-tools install**: added non-sudo fallback and manual install prompt for
  environments without elevated permissions

---
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **SKILL.md: guardian.conf placeholder resolution** — added explicit table showing how to
  resolve `FALLBACK_CHANNEL` and `FALLBACK_TARGET` from conversation context before writing
  the conf file; Step 4 now clearly states placeholders must be substituted before running
- **inotify-tools install**: added non-sudo fallback and manual install prompt for
  environments without elevated permissions

---
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **SKILL.md: guardian.conf placeholder resolution** — added explicit table showing how to
  resolve `FALLBACK_CHANNEL` and `FALLBACK_TARGET` from conversation context before writing
  the conf file; Step 4 now clearly states placeholders must be substituted before running
- **inotify-tools install**: added non-sudo fallback and manual install prompt for
  environments without elevated permissions

---
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
- Startup validation is also skipped while maintenance mode is active

- **Upgrade-aware notifications**
  - New managed restart flag type `upgrade` (write `echo "upgrade" > /tmp/guardian-managed-restart` before upgrading)
  - When gateway recovers after an upgrade, notification reads "OpenClaw upgrade detected — gateway restarted automatically" instead of the generic restart message
  - Distinguishes planned upgrade restarts from crash recovery and manual restarts
Confidence
80% confidence
Finding
Using a predictable file in /tmp as a coordination flag can enable tampering by other local processes or users on the same host. If the scripts trust that flag without ownership and symlink checks, an attacker may spoof restart state, suppress or alter notifications, or interfere with guardian control flow.

Ssd 3

Medium
Confidence
96% confidence
Finding
The notification text tells users to forward the full alert back to the AI, and the example includes timestamps, backup names, and recent operational logs. This encourages exfiltration of environment and diagnostic details into model context, where they may be retained, processed by other tools, or used to guide further system actions.

Ssd 3

Medium
Confidence
96% confidence
Finding
This repeated instruction reinforces a workflow where users disclose recovery alerts directly to the AI, increasing the likelihood that sensitive runtime details are pasted into chat. Because the surrounding examples include failure context and service state, the practice meaningfully raises the chance of unnecessary information disclosure.

Static analysis

Detected: suspicious.destructive_delete_command

Documentation contains a destructive delete command without an explicit confirmation gate.

Warn
Code
suspicious.destructive_delete_command
Location
README.en.md:163

Documentation contains a destructive delete command without an explicit confirmation gate.

Warn
Code
suspicious.destructive_delete_command
Location
README.md:166

Documentation contains a destructive delete command without an explicit confirmation gate.

Warn
Code
suspicious.destructive_delete_command
Location
SKILL.md:295