【Solar应急预警】开源智能体OpenClaw(小龙虾)内网暴露风险剖析与多维排查指南
一、 背景概述与预警通报OpenClaw 是一款开源的本地 AI Agent 框架。与传统的云端大模型助手不同它支持通过自然语言直接操控宿主机能够自主完成本地文件读写、网页浏览、Shell 命令执行等高阶操作。然而正是这种自动化与高权限的特性使其在缺乏访问控制的企业内网中成为了一把双刃剑。2026年2月工业和信息化部网络安全威胁和漏洞信息共享平台NVDB发布了关于防范 OpenClaw 开源 AI 智能体安全风险的紧急预警明确指出由于 OpenClaw 在部署时“信任边界模糊”且具备自身持续运行、自主决策、调用系统和外部资源等特性在缺乏有效权限控制的情况下极易引发网络攻击、信息泄露、系统受控等一系列安全问题。工信部网络安全威胁和漏洞信息共享平台NVDB发布的安全预警提示二、 核心安全风险剖析与普通办公软件不同OpenClaw 这类 AI Agent 在企业环境中的风险主要集中在其运行机制与生态开放性上2.1 高权限的“可执行代理”OpenClaw 并不是一个简单的对话框而是一个具备系统操作能力的执行节点。为了完成自动化任务它默认需要访问本地文件、调用系统终端甚至会接触到开发者的APIKey、云平台访问令牌及本地缓存数据。如果它运行在高权限账户下一旦出现误操作或被恶意利用将直接成为攻击者在内网收集信息与横向移动的跳板。2.2 开放生态引发的供应链投毒OpenClaw 支持通过 Skills技能、插件和扩展模块不断增强能力。这一机制虽然提升了灵活性但也引入了严重的供应链安全隐患。 在近期的真实安全事件中已出现名为 “GhostClaw” 的攻击案例。攻击者将包含恶意 RAT远程访问木马的组件伪装成 OpenClaw 安装包发布在 npm 平台上。用户一旦下载安装程序在后台便会窃取浏览器凭证、SSH 密钥及加密钱包等核心敏感数据实现了从“辅助工具”到“窃密后门”的转变。Cyber Security News针对GhostClaw事件的描述2.3 部署配置不当导致的网络暴露OpenClaw 的 Gateway 默认监听18789端口Control Service 等组件也可能占用8000或9090端口。在默认配置文档中如~/.openclaw/openclaw.json为了方便远程调用或测试部分研发人员会将绑定地址从本地回环127.0.0.1修改为局域网或公网0.0.0.0且未配置任何身份认证。这种行为会直接将一个具备系统级控制权的接口暴露在内网甚至公网中。openclaw.json配置文件示例三、 传统排查方式的盲区在收到预警后许多企业的安全团队开始使用端口扫描脚本在内网寻找 OpenClaw。但大量反馈表明单纯依赖“默认端口扫描”极易产生漏报主要原因在于以下两个盲区3.1 仅监听本地回环地址如果使用者遵循了最基础的安全习惯将应用仅绑定在本地回环地址127.0.0.1controlUI: { allowedOrigins: [ http://localhost:18789, [http://127.0.0.1:18789](http://127.0.0.1:18789) ] }此时该服务不会对局域网开放网络侧扫描工具完全无法探测到该端口的存活但程序依然在员工的终端上高权限运行。3.2 规避默认端口具备一定安全意识或为避免端口冲突的开发者会主动修改默认的18789端口。如果检测脚本仅对单一固定端口进行探测同样会直接漏检。四、 企业级多维自查与检测方案鉴于上述盲区Solar 应急响应团队建议企业采用“终端核查 网络扫描 流量审计”相结合的联动排查思路从易到难、从面到点进行全面治理。4.1 终端合规检测精准度最高适用于 EDR/MDM 下发如果你拥有域控、Jamf 或 EDR 设备的统一下发权限直接在主机侧进行排查是最彻底的方式。此方案不受网络端口绑定状态的影响。目前社区已有开源的检测脚本如 GitHub 上的knostic/openclaw-detect提供了适用于多平台的检测逻辑。核心检测路径扫描是否存在~/.openclaw/openclaw.json或~/.config/openclaw等默认配置目录。进程特征检测是否存在包含openclaw、clawdbot、moltbot参数的node进程。利弊分析精准度极高无视网络隔离缺点是执行速度相对较慢需要管理员权限。注在执行第三方脚本前务必先进行代码审计防范二次供应链投毒。# 检测脚本地址 https://github.com/knostic/openclaw-detect4.2 网络端主动扫描适用于大网段快速摸排对于尚未部署完善终端管理体系的环境主动扫描仍是快速收敛暴露面的首选方案。方法 A使用 Nmap 快速探测利用 Nmap 对内网存活资产的18789、8000等高危端口进行探测。# 扫描 192.168.146.0/24 网段的 18789 端口仅输出开放状态的主机 nmap -p 18789 --open -T4 192.168.146.0/24 -oG - | grep /open nmap -p 18789 --open -T4 192.168.146.0/24 -oG - | findstr 18789/open # Windows命令执行使用 Nmap 探测发现内网主机 192.168.146.154 开放了 18789 默认端口方法 BPython 深度特征验证脚本为了降低 Nmap 端口扫描带来的误报其他业务恰好使用了该端口可以使用结合了 HTTP 探针验证的 Python 扫描脚本。 该脚本的逻辑分为两步首先验证端口是否开放随后向目标发送探测请求如/health、/v1/agents、/v1/models并解析 HTTP Body 中是否包含openclaw-app或status: ok等特有指纹。# -*- coding: utf-8 -*- OpenClaw小龙虾内网探测工具 - 端口扫描 HTTP 特征双重验证 仅限企业内部授权资产自测与安全审查严禁未经授权使用。 版本号V1.0 授权给Solar应急响应团队 LOGO r YYYYYYXXXYYYYYYYYYYYYYYYYYYYYYYYYYXQ XYYYXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXYYYYJ ~X XXYYYYYXzXYYYY JYYXzzYYYYYYQ $$ YYYYYYXzzXYYYU |\| \\| 8JYYYzczYYYYXYr YXXXXYYYYYJX(|\\\\\/\/) t\\\\\\\\| JYYYYYXXXYY UXYXYY ||\\\|\\\\||\\\\\ b\\\\\||\\\||\\\| YXYYYY UXYXYY \||\\\\\\\\\\\||/\/ \\\||\\\\\\||\\\\/c YXYYXU UXYXYY //\\\\///||\\\\\\(/ /(\\\\\||\\\\\/ YXYYXU YYYXYU (/\\\\\/\\\/\||\\|/ /|\||\\///j \\|/ YXYYXU XYXYYY b/|\\\\\ )\\\\\(/ /(//\/\ |\\\\\(/ YXYYYX mYXYXY /|\\\\\\\\\ |\|/ \|| \\/\\\||\\|\ cYXYXYU YXYXYJ /\\\\\\\||\\\\\ /\\\\\||\\\\\\\/ YYYYXY YYXYYY //\||\\\\\\||\\\\\ /\\\||\\\\\\\\\|/ JYXYXYY YXYXYU \\\\\\||\\\\\\|(\ /(\\\\\\\\|\\\\\/ YXYYXY YYXYXY /\\\\\||\\\|\ /|\\\\||/\//\\|/ UYXYXYY XYXYXY f/t |\\\\\|(/ /(||\\\\\ /(|/b UYXYXYX YYXYYY j/\\\/ \/\|/ /x t\\\\\(\/ YXXYXYU YYXYYYJ /\(\\\// | /|\\/ }\/\|/} YYXYXYY UYXXXYY /\\((\\\\\f J\\\\\||(\\/ zYYXXYYc zYYXXXYX /\\|\||\|/ /|||\\|\\/ YYXXXYU YYXXXYYX \\\|\\(/ /|\||\\\ YYYXXXYX mYYXXXYYY \\\\(/ /(\\\\ CYYYzXYYX JYYXzXYYYJ |\|/ \|| XYYXzXYYY 0YYYXzXYYYJ UYYYYzzYXYU YYYYzzXYYYYXQYYYYYXcXYYYX YYYYYXzXYYYXzXYYYYY XXXYYYYYYYYYY import socket import ipaddress import concurrent.futures import time import json import re import argparse try: import urllib.request import urllib.error except ImportError: urllib None # ---------------- 配置区 ---------------- TARGET_PORT 18789 # OpenClaw 默认端口 TIMEOUT 0.5 # 端口扫描超时秒 HTTP_TIMEOUT 2 # HTTP 请求超时秒 MAX_THREADS 100 # 端口扫描并发线程数 HTTP_WORKERS 20 # HTTP 验证并发数 # ---------------------------------------- # HTTP 探测路径按优先级排序先试开销小的 HTTP_PROBE_PATHS [ /health, # 健康检查通常无需认证 /v1/agents, # OpenClaw 独有接口 /v1/models, # OpenAI 兼容可检测 openclaw 相关 model id ] defcheck_port_open(ip): 仅检测端口是否开放不建立完整连接后等待。 成功返回 IP 字符串失败返回 None。 try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.settimeout(TIMEOUT) result s.connect_ex((str(ip), TARGET_PORT)) if result 0: return str(ip) except Exception: pass returnNone defhttp_probe(ip, path/health): 对指定 IP 发送 GET 请求返回 (status_code, body_text, headers_dict) 或 (None, None, None)。 url fhttp://{ip}:{TARGET_PORT}{path} try: req urllib.request.Request(url, methodGET) req.add_header(User-Agent, OpenClaw-Scanner/1.0) with urllib.request.urlopen(req, timeoutHTTP_TIMEOUT) as resp: body resp.read().decode(utf-8, errorsignore) headers dict(resp.headers) return resp.status, body, headers except urllib.error.HTTPError as e: # 401/403 等也说明该端口有 HTTP 服务在响应 try: body e.read().decode(utf-8, errorsignore) except Exception: body return e.code, body, dict(e.headers) if e.headers else {} except (urllib.error.URLError, OSError, socket.timeout, Exception): returnNone, None, None defis_openclaw_response(status, body, path): 根据 HTTP 响应判断是否为 OpenClaw 实例。 返回 (是否匹配, 匹配原因描述)。 if body isNoneor body : returnFalse, body_lower body.lower() # 常见 OpenClaw 相关关键词 openclaw_indicators [ openclaw, openclaw-agent-id, rstatus:\s*ok, # /health 常见返回 agents, # /v1/agents 返回 rdata:\s*\[.*openclaw, # /v1/models 中可能包含 openclaw:main 等 invalid_request_error, # 文档中的错误类型 ] for indicator in openclaw_indicators: if re.search(indicator, body_lower, re.IGNORECASE | re.DOTALL): returnTrue, f响应含特征: {indicator[:30]} # /health 进一步特征判断 if path /health: # 1) body 中直接包含 openclaw-app ifopenclaw-appin body: returnTrue, health 响应中包含 openclaw-app # 2) status 为 200 且 JSON 结构中带 status 字段 if status 200: try: obj json.loads(body) if isinstance(obj, dict) andstatusin obj: returnTrue, fhealth 返回 status 字段: {obj.get(status)} except json.JSONDecodeError: pass returnFalse, defverify_openclaw(ip): 对单个 IP 进行 HTTP 特征验证。 返回 (是否确认为 OpenClaw, 详细信息)。 for path in HTTP_PROBE_PATHS: status, body, headers http_probe(ip, path) if status isNone: continue is_match, reason is_openclaw_response(status, body, path) if is_match: detail fpath{path} status{status} - {reason} returnTrue, detail # 可选检查 Server 头 server (headers or {}).get(Server, ) if server andopenclawin server.lower(): returnTrue, fServer 头: {server} returnFalse, defscan_network(subnet): 扫描指定网段先端口扫描再对开放端口进行 HTTP 验证。 print(f[*] 扫描网段: {subnet}) print(f[*] 目标端口: {TARGET_PORT}) print(f[*] 端口扫描线程: {MAX_THREADS}HTTP 验证并发: {HTTP_WORKERS}\n) port_open_ips [] confirmed_openclaw [] try: network ipaddress.IPv4Network(subnet, strictFalse) except ValueError as e: print(f[!] 网段格式错误: {e}) print([!] 请使用 CIDR 格式例如: 192.168.1.0/24) return confirmed_openclaw # ---------- 阶段一端口扫描 ---------- start_time time.time() with concurrent.futures.ThreadPoolExecutor(max_workersMAX_THREADS) as executor: future_to_ip {executor.submit(check_port_open, ip): ip for ip in network.hosts()} for future in concurrent.futures.as_completed(future_to_ip): ip future_to_ip[future] try: result future.result() if result: port_open_ips.append(result) print(f[] 端口开放: {result}:{TARGET_PORT}) except Exception: pass port_time time.time() - start_time ifnot port_open_ips: print(\n[*] 未发现开放端口无需 HTTP 验证。) print( * 50) print(f耗时: {port_time:.2f} 秒) return confirmed_openclaw # ---------- 阶段二HTTP 特征验证 ---------- print(f\n[*] 对 {len(port_open_ips)} 个主机进行 HTTP 特征验证...) http_start time.time() with concurrent.futures.ThreadPoolExecutor(max_workersHTTP_WORKERS) as executor: future_to_ip {executor.submit(verify_openclaw, ip): ip for ip in port_open_ips} for future in concurrent.futures.as_completed(future_to_ip): ip future_to_ip[future] try: is_openclaw, detail future.result() if is_openclaw: confirmed_openclaw.append(ip) print(f[!] 确认 OpenClaw: {ip}:{TARGET_PORT} | {detail}) else: print(f[-] 仅端口开放非 OpenClaw: {ip}:{TARGET_PORT}) except Exception as e: print(f[-] 验证异常 {ip}: {e}) total_time time.time() - start_time print(\n * 50) print(f端口扫描耗时: {port_time:.2f} 秒) print(fHTTP 验证耗时: {time.time() - http_start:.2f} 秒) print(f总耗时: {total_time:.2f} 秒) print(f端口开放: {len(port_open_ips)} 个) print(f确认为 OpenClaw: {len(confirmed_openclaw)} 个) print( * 50) return confirmed_openclaw defmain(): parser argparse.ArgumentParser( descriptionOpenClaw小龙虾内网探测工具 - 端口扫描 HTTP 特征验证, formatter_classargparse.RawDescriptionHelpFormatter, epilog 示例: python scan_openclaw.py 192.168.1.0/24 python scan_openclaw.py 10.0.0.0/16 python scan_openclaw.py 172.16.0.0/24 ) parser.add_argument( subnet, nargs?, help目标网段CIDR 格式如 192.168.1.0/24 ) args parser.parse_args() target_subnet (args.subnet or).strip() ifnot target_subnet: print(版本号V1.0) print(授权给Solar应急响应团队) print(LOGO) print( OpenClaw小龙虾内网探测工具 --------------------------------------------- 端口扫描 HTTP 特征双重验证 声明仅限企业内部授权资产自测严禁未经授权使用。 ) target_subnet input(请输入需要扫描的内网网段 (如 192.168.1.0/24): ).strip() ifnot target_subnet: print(未输入有效网段程序退出。) return else: print(版本号V1.0) print(授权给Solar应急响应团队) print(LOGO) print(f OpenClaw小龙虾内网探测工具 --------------------------------------------- 目标网段: {target_subnet} ) if urllib isNone: print([!] 需要 urllibPython 标准库以进行 HTTP 验证。) return scan_network(target_subnet) if __name__ __main__: main()基于python编写的内网探测OpenClaw资产脚本利弊分析通过“端口存活协议特征”双重验证极大降低了误报率结果高度可信但弊端依然存在它无法探测到绑定在127.0.0.1或修改了非常规端口的实例。4.3 全流量审计与被动监测应对深度隐藏适用于 NDR/流量分析设备无论使用者如何隐藏进程或修改端口只要 OpenClaw 产生交互网络流量就会留下痕迹。结合科来等专业全流量分析厂商的研究企业可以在流量审计设备上配置以下特征规则API请求与协议头特征深度解析 HTTP 请求关注User-Agent是否包含特定客户端标识或是否存在X-Stainless-Retry-Count、X-Stainless-OS等大模型调用框架专属 Header。通信交互上下文监控访问open.feishu.cn等开放平台接口的流量若该流量与外部大模型域名的 API 请求存在紧密的时序关联可判定为智能体正在进行指令交互。加密隧道异常部分实例可能通过 FRP 或 Ngrok 建立反向隧道隐藏通信。需结合数据包长度分布、时序特征等元数据识别异常的隐蔽外联。以上流量特征提取思路参考自科来《内网藏“暗爪”OpenClaw检测与治理全攻略》一文五、 防御建议与安全加固面对具备自主执行能力的 AI 智能体传统的基于特征码的防御策略已显被动。对于确有研发和测试需求的企业我们建议1.物理与逻辑隔离严禁在涉及核心业务数据、生产环境的终端上直接运行 OpenClaw。所有测试必须在隔离的沙箱、虚拟机或独立的容器环境中进行严格控制宿主机权限。2.细粒度网络阻断利用防火墙和微隔离策略对非必须的网关端口及异常的跨网段横向请求进行阻断限制测试环境向外联络的域名白名单。3.插件准入机制建立严格的第三方 AI 插件和 Skills 审计流程禁止开发人员随意拉取来源不明的执行脚本从源头切断供应链投毒风险。