T01 · Skill Instruction Hijacking
- Location
SKILL.md:57- Finding
Agent instruction hierarchy and browser tool hijacking
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill has a coherent remote-browser purpose, but it asks for broad root-level control and creates persistent remote access that users should review carefully before installing.
Install only on a disposable or dedicated host, not a production server or machine with sensitive accounts. Avoid giving SSH passwords or blanket passwordless sudo; prefer running reviewed commands yourself. Keep noVNC off the public Internet unless protected by SSH tunnel, VPN, TLS, strong access control, and firewall source restrictions, and disable/remove the services when finished.
SKILL.md:57Agent instruction hierarchy and browser tool hijacking
SKILL.md:504Persistent privileged remote-browser services
SKILL.md:256Unrestricted passwordless root privilege grant
SKILL.md:186Unnecessary cloud instance metadata probing
SKILL.md:396Public noVNC service uses plaintext transport and retained plaintext credentials
SKILL.md:443Root-owned Chromium runs with its security sandbox disabled
SKILL.md:296Unpinned third-party components are installed and executed with elevated privileges
The skill accesses an internal Alibaba metadata IP to detect cloud environment. Even though the immediate intent is environment detection, internal metadata endpoints are privileged network resources and contacting them expands the attack surface for SSRF-like behavior and cloud information disclosure.
# 检测是否云服务器(腾讯云/阿里云/AWS metadata)
if curl -s --connect-timeout 2 http://metadata.tencentyun.com/latest/meta-data/ 2>/dev/null | grep -q .; then
echo "ENV_TYPE=CLOUD"
elif curl -s --connect-timeout 2 http://100.100.100.200/latest/meta-data/ 2>/dev/null | grep -q .; then
echo "ENV_TYPE=CLOUD"
elif curl -s --connect-timeout 2 http://169.254.169.254/latest/meta-data/ 2>/dev/null | grep -q .; then
echo "ENV_TYPE=CLOUD"
The skill probes cloud metadata endpoints, including 169.254.169.254, to classify the environment. Requests to metadata services are sensitive because they can expose cloud instance details or credentials if the probing is expanded, redirected, or repurposed, and normalizing metadata access in a skill is risky.
echo "ENV_TYPE=CLOUD"
elif curl -s --connect-timeout 2 http://100.100.100.200/latest/meta-data/ 2>/dev/null | grep -q .; then
echo "ENV_TYPE=CLOUD"
elif curl -s --connect-timeout 2 http://169.254.169.254/latest/meta-data/ 2>/dev/null | grep -q .; then
echo "ENV_TYPE=CLOUD"
# 检测是否 NAS(群晖 Synology / QNAP 威联通)
elif [ -f /etc/synoinfo.conf ]; then
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.
if [ "$(id -u)" = "0" ]; then
echo "PERMISSION_OK: 当前是 root 用户"
elif command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
echo "PERMISSION_OK: 当前用户可免密 sudo"
else
echo "PERMISSION_DENIED: 当前用户不是 root,且无法免密 sudo。"
Piping a generated sudoers rule directly into sudo tee automates a highly privileged configuration change with no scoping and no validation. In an agent context, this is especially dangerous because it lowers friction for granting unrestricted root-equivalent access through a single copied command.
引导用户在服务器终端执行一行命令即可,密码不离开用户机器:
echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/hermes-deploy
完成后 Agent 即可通过 sudo 继续部署。部署完成后执行 sudo rm /etc/sudoers.d/hermes-deploy 收回权限。
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).
echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/hermes-deploy
完成后 Agent 即可通过 `sudo` 继续部署。部署完成后执行 `sudo rm /etc/sudoers.d/hermes-deploy` 收回权限。
**备选:提供 SSH 凭证**
The skill explicitly asks for SSH credentials as a fallback and does not place strong, repeated warnings around highly sensitive credential handling, redaction, or safer alternatives. This is dangerous because it normalizes collection of server passwords inside an agent workflow that also performs privileged remote administration and network exposure.
The invocation text tells the agent to automatically install and run a high-privilege remote browser stack with very broad trigger wording and minimal user scoping. Because the skill provisions services, opens ports, and configures persistence, an overly broad activation path raises the chance of unintended execution on the wrong host or in the wrong context.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
- **可视化浏览器**:Chromium 运行在 Xvfb 虚拟屏幕上,用户可通过 noVNC 网页实时查看画面。
- **AI 可控**:Agent 通过 CDP 连接 `127.0.0.1:9223`,可执行打开网页、点击、输入、读取页面、截图等操作。
- **人机协作**:遇到登录、二维码、滑块、验证码时,用户可在 noVNC 中手动处理,处理完成后 AI 继续执行。
- **权限预检**:安装前先确认 root/sudo 权限,权限不足时主动提醒用户授权方式,避免半安装状态。
- **安全边界**:默认只建议开放 noVNC 的 `6080/tcp`,CDP 调试端口 `9223/tcp` 不建议暴露到公网。
- **完成反馈**:部署完成后,Agent 必须先主动发送 noVNC 访问地址、访问密码、开机自启状态和端口开放提醒;截图作为最后一步补充确认发送,截图失败不得阻塞前面的核心信息。
- **Windows 本机模式**:Agent 自动启动 Edge/Chrome 远程调试端口,通过 CDP 接管浏览器,本机屏幕实时可见,截取当前页面反馈,无需安装额外组件。
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
- **可视化浏览器**:Chromium 运行在 Xvfb 虚拟屏幕上,用户可通过 noVNC 网页实时查看画面。
- **AI 可控**:Agent 通过 CDP 连接 `127.0.0.1:9223`,可执行打开网页、点击、输入、读取页面、截图等操作。
- **人机协作**:遇到登录、二维码、滑块、验证码时,用户可在 noVNC 中手动处理,处理完成后 AI 继续执行。
- **权限预检**:安装前先确认 root/sudo 权限,权限不足时主动提醒用户授权方式,避免半安装状态。
- **安全边界**:默认只建议开放 noVNC 的 `6080/tcp`,CDP 调试端口 `9223/tcp` 不建议暴露到公网。
- **完成反馈**:部署完成后,Agent 必须先主动发送 noVNC 访问地址、访问密码、开机自启状态和端口开放提醒;截图作为最后一步补充确认发送,截图失败不得阻塞前面的核心信息。
- **Windows 本机模式**:Agent 自动启动 Edge/Chrome 远程调试端口,通过 CDP 接管浏览器,本机屏幕实时可见,截取当前页面反馈,无需安装额外组件。
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
if [ "$(id -u)" = "0" ]; then
echo "PERMISSION_OK: 当前是 root 用户"
elif command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
echo "PERMISSION_OK: 当前用户可免密 sudo"
else
echo "PERMISSION_DENIED: 当前用户不是 root,且无法免密 sudo。"
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
if [ "$(id -u)" = "0" ]; then
echo "PERMISSION_OK: 当前是 root 用户"
elif command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
echo "PERMISSION_OK: 当前用户可免密 sudo"
else
echo "PERMISSION_DENIED: 当前用户不是 root,且无法免密 sudo。"
The skill instructs the user to grant full passwordless sudo to the current account via a sudoers drop-in. This creates a powerful privilege-escalation path that can be abused by any process or later prompt execution under that account, far beyond the immediate deployment need.
引导用户在服务器终端执行一行命令即可,密码不离开用户机器:
echo "$(whoami) ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/hermes-deploy
完成后 Agent 即可通过 sudo 继续部署。部署完成后执行 sudo rm /etc/sudoers.d/hermes-deploy 收回权限。
The skill stores the generated noVNC password in cleartext at /root/.novnc_password for later disclosure. Even though root-only permissions reduce exposure, plaintext credential storage on disk increases the risk of credential theft through backups, later compromise, or accidental disclosure by the agent.
# 8 位随机密码(字母+数字混合)
NOVNC_PASS=$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 8)
echo -n "$NOVNC_PASS" > /root/.novnc_password
chmod 600 /root/.novnc_password
# 用 x11vnc 自己的工具生成 VNC 密码文件
x11vnc -storepasswd "$NOVNC_PASS" /root/.vncpasswd
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
# 用 x11vnc 自己的工具生成 VNC 密码文件
x11vnc -storepasswd "$NOVNC_PASS" /root/.vncpasswd
chmod 600 /root/.vncpasswd
echo "noVNC 访问密码已生成:$NOVNC_PASS"
echo "明文存储于:/root/.novnc_password(仅 root 可读)"
The skill enables persistent systemd services for a remote browser, VNC server, and websockify listener at boot. Persistence magnifies risk because exposed services and privileged browser automation remain available after reboot, potentially outside the user's immediate awareness.
EOF
systemctl daemon-reload systemctl enable --now xvfb.service x11vnc.service novnc.service chromium-remote.service
验证(应全部 `active`):
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.
import websocket
url = 'https://example.com'
tabs = json.load(urllib.request.urlopen('http://127.0.0.1:9223/json'))
page = next(t for t in tabs if t.get('type') == 'page')
ws = websocket.create_connection(
page['webSocketDebuggerUrl'],
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.
import websocket
url = 'https://example.com'
tabs = json.load(urllib.request.urlopen('http://127.0.0.1:9223/json'))
page = next(t for t in tabs if t.get('type') == 'page')
ws = websocket.create_connection(
page['webSocketDebuggerUrl'],
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
DISPLAY=:99 import -window root /tmp/remote-browser.png
mkdir -p ~/.openclaw/media/qqbot
cp /tmp/remote-browser.png ~/.openclaw/media/qqbot/remote-browser.png
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
DISPLAY=:99 import -window root /tmp/remote-browser.png
mkdir -p ~/.openclaw/media/qqbot
cp /tmp/remote-browser.png ~/.openclaw/media/qqbot/remote-browser.png