那份字典早就知道你的主目录
F5 Labs 在一个月里记录到针对暴露的 Vite 开发服务器的 807 次攻击和 32,000 条事件,用的是一个查询字符串小把戏,径直从 Vite 自己的 deny-list 前面走了过去。扫描器要找的不是你的应用。它们用绝对路径索取 /home/ubuntu/.aws/credentials,索取 /proc/self/environ,索取 terraform.tfstate。在 Bromure Agentic Coding 的工作区里,那个端口面对的是一台私有交换机,而字典想要的那个文件里没有任何密钥。
这个攻击者不给你寄包,也不给你寄压缩档。是你自己的开发服务器在监听,而一个陌生人 点着名向它要文件。由哪台机器来回答,决定了对方拿到什么。
你让代理把前端跑起来,好让你看一眼。它敲下 npm run dev,绑好端口,加载页面,你则
回头去看那份 diff。在那个循环的某处,在某个 docker-compose.yml 里,或者在你几周前
为了让手机也能看预览而加上的 --host 标志里,服务器绑上了每一张网卡,而不是只绑
回环。十二分钟后,某个自称 Googlebot 的东西向你的开发服务器索取
/@fs/../.env?raw??,并拿到一个 HTTP 200。
F5 Labs 在 9 月 11 日公布了数字。 在 2026 年 8 月这单单一个月的传感器数据里,他们的蜜罐记录到 807 次按会话分组的攻击, 以及大约 32,000 条针对暴露的 Vite 开发服务器的原始事件,而此前三个月的基线是 1,732 条。也就是说,为了一个缺陷,流量在一个月之间变成了十八倍。BleepingComputer 在 9 月 14 日做了报道。
一段从 deny-list 旁边绕过去的查询字符串
Vite 通过一条叫 /@fs/ 的内部路由,把宿主文件系统上的文件发出去;开发服务器正是靠
它,把位于项目根目录之外的模块交给你的编辑器。正因为这条路由哪里都够得着,Vite 随附
了一份 deny-list,也就是 server.fs.deny,用来挡掉那些显而易见的目标:.env 文件、
证书、私有源码。
4 月 7 日公布的 CVE-2026-39364,让攻击者只要给请求缀上一段查询字符串,就能跳过那份 deny-list。F5 这样描述它的机制:
服务器处理该请求,规范化路径,并在访问校验期间去掉或错误解析查询字符串,因而没能 触发 server.fs.deny 检查。
服务器没有落实 deny-list 过滤,并以 HTTP 200 响应发出目标文件。
这个缺陷影响 Vite 7.1.0 到 7.3.2,以及 8.0.5 之前的 8.x。F5 在真实流量里截到了这些
请求形状,每一条都短得一行读完:GET /@fs/.env?raw??、GET /@fs/../.env?raw??、
GET /@fs/..%252f..%252f..%252f..%252froot/.env?raw??,以及
GET /@fs/..%252f..%252f..%252f..%252fproc/self/environ?raw??。同一套工具里的其他
变体则用 ?import&raw、?import&url&inline、?inline&import 和 ?raw?import。
那些参数把戏各自带着自己的 CVE 编号:CVE-2025-30208、CVE-2025-31125 和 CVE-2024-45811,是同一条路由上三个更早的绕过,至今仍装在同一批扫描器里。经营这支 扫描机群的人并没有为一个新缺陷重新造工具。他只是在一份早就有的文件上又加了一行。
字典是一张开发者机器的地图
读一读扫描器索取的东西,并留意其中有多少其实跟你的应用无关。
它们索取 .env、.env.local、.env.production、.env.development 和
.env.staging。索取 terraform.tfstate、terraform.tfvars、
.terraform/terraform.tfstate、serverless.yml 和
.serverless/serverless-state.json。索取 .azure/credentials 和
.azure/accessTokens.json。索取 /etc/passwd、/proc/1/environ、
/proc/self/cwd/.env 和 /proc/self/environ。最后那条路径装的是开发服务器进程
自己的环境块,也就是你的 shell 导出的 API_KEY 最终落脚的地方。
接着它们会沿着开发者进程可能所属的主目录清单,一个一个索取 AWS 凭据:
/root/.aws/credentials、/home/ec2-user/.aws/credentials、
/home/ubuntu/.aws/credentials、/home/node/.aws/credentials、
/home/www-data/.aws/credentials、/home/admin/.aws/credentials、
/home/debian/.aws/credentials、/var/www/.aws/credentials、
/usr/src/app/.aws/credentials、/app/.aws/credentials。然后是 .aws/config、
.aws/credentials.backup、.aws/credentials.bak、.aws/sso/cache/、
rootkey.csv、aws-exports.js 和 amplifyconfiguration.json。
那些路径清点的是一台开发者机器,按用户名逐一列举,而 Vite 只是那道门。缺陷本身是 附带的;同一条路由上三个更老的缺陷,就搭在同一批请求里一起来。运营者赌的是:一个在 可路由地址上监听的进程,跑在一个主目录里放着真密钥的用户底下。
这些流量打扮得足以撑过对日志的随意一瞥。F5 记录到伪造的 User-Agent 头,在
Googlebot/2.1、ClaudeBot/1.0、GPTBot/1.4、PerplexityBot/1.0、
OAI-SearchBot/1.3 和 Amazonbot/0.1 之间轮换,还有伪造的 X-Forwarded-For 和
X-Real-IP 值,用来绕过 IP 允许列表。来源落在 Google Cloud 的 34.x 和 35.x 网段,
分布在好几个区域,以美国的 17,297 条事件居首,其次是比利时的 4,407 和荷兰的 4,011。
这个月,你访问日志里自称是 AI 爬虫的那一行,并不足以证明真有爬虫发过它。
F5 的建议里有两条是架构问题
F5 以五条建议收尾。其中三条平常而正确:升级到 7.3.2 或 8.0.5、在边缘过滤 /@fs/、
用反向 DNS 校验爬虫而不是相信头部。另外两条讲的不是一件你做得完的事,而是一种你得
一直保持住的姿态。
确保开发服务器不绑定到外部网卡。审计 Docker compose 配置、Kubernetes ingress 规则以及云端安全组。
轮换已暴露的机密:如果一台未打补丁的 Vite 开发服务器在 2026 年 8 月期间可从外部 网络访问,请把本机的 .env 变量、AWS 凭据、Azure 访问令牌和 Terraform 状态文件 视为可能已泄露。
第一条要你对每一个端口、在每一份 compose 文件里、跨越每一条分支、在项目活着的每一天
都守住一个承诺;而此刻敲下 npm run dev 的,往往是代理而不是你。第二条问的是事后你
要做什么,并自己给了答案:把那台机器看得到的东西全部轮换。
如果端口是在别的地方打开,而字典点名的那些文件里没有任何值得轮换的东西,这两件事都 会轻松许多。
Bromure 的工作区把端口放在哪里
Bromure Agentic Coding 让编码代理跑在你 Mac 上一台硬件虚拟化的 Linux 虚拟机里,安全 控制则放在那道边界的宿主一侧。其中有两项回应了这场行动。
开发服务器绑在一台私有交换机的内侧。 在默认的 NAT 模式下,每台工作区虚拟机都接到
同一台进程级的软件 L2 交换机上,复用在单一 vmnet 网卡上,位于一个私有子网。除非你
自己的局域网已经占用,否则那个子网就是 192.168.64.0/24;Bromure 在上面跑自己的 DHCP
服务器,每个工作区都保有确定的 MAC 和稳定的租约。手册写下了它的后果:你的 Mac 够得着
那些虚拟机,你的物理局域网看不到它们,而除非你自己发布某个服务,否则从别处进来的连接
根本不可能。在那台虚拟机里绑上 0.0.0.0 的代理,绑的是它自己拥有的每一张网卡,而每一
张都面对一台从你的笔记本开始、也在你的笔记本结束的交换机。你没有安全组要审计,因为你
没有一条进来的路要守。
你仍然看得到什么在监听,而那是一份清单,不是一场审计。 工作区仪表板上有一张
Listening Ports 卡片,把访客端每一个可从外部访问的套接字,以 <虚拟机地址>:<端口> 的
端点形式列出,还能一键复制。这把 F5 的第 2 条建议,从一场你得排进日程的审计,变成一张
你顺手扫一眼的卡片,而且每一秒半就从访客端刷新一次。当你确实想让全世界看到预览时,一个
看起来像 HTTP 的服务会多出一颗地球按钮,在一次性的同意对话框之后,通过 Cloudflare 快速
隧道发布那一个服务。你是在宿主上,一个服务一个服务地点击来公开它,而不是靠一份
compose 文件里活着的标志。
你当初伸手去拿 --host 的理由,仍然保得住。那台用完即弃的 Chromium 边车跟工作区虚拟机
共享同一个 L2 网段,所以内嵌浏览器是用虚拟机的地址去加载代理的开发服务器。不是
localhost,因为浏览器跑在另一台机器上。
如果真有其他机器需要连到这台虚拟机,Bridged 模式会把它接上你的物理局域网。你在宿主上的 工作区编辑器里逐个工作区设置这件事,而且启动时若网卡不可用,它会退回 NAT。这个选择是在 一个面板里做的,不是在一份代理改得动的配置文件里。
那如果你是刻意发布这个服务呢
有时候你确实想把预览放到互联网上,给客户或同事看。那就点下地球、打开隧道,让扫描器 找上门。顺着字典一条一条往下走,看看回来的是什么。
.env 和 /proc/self/environ 返回的是工作区的环境,而里面每一份凭据都是假的。
Bromure 用真实值加上每次安装专属的 32 字节盐,经 HKDF-SHA256 导出每一个替身,并保留
客户端校验器期待的形状:Anthropic 的密钥读起来是 sk-ant-api03-brm-…,GitHub 的令牌
是 ghp_ 加 36 个字符,GitLab 则是 glpat- 加 20 个。Bromure 把那些赝品写进环境变量,
也写进 ~/.git-credentials、~/.docker/config.json、~/.kube/config 以及各个 MCP
配置。真实值从不进入那台虚拟机;它们加密留在 Mac 上,由宿主一侧的代理在最后一刻把每
一个换到链路上,而且只限它所属的那个目标主机。
/home/ubuntu/.aws/credentials 是最锋利的一条,因为 /home/ubuntu 正是 Bromure
工作区虚拟机的主目录。扫描器猜对了是哪个用户在跑那台服务器。文件却依然不在那里。
Bromure 的 AWS 配置根本不写凭据文件;它写的是 ~/.aws/config,里面一行
credential_process 指向一个辅助程序,那个程序通过宿主套接字交出你真正的访问密钥 ID,
配上一把四十个字符的假秘密密钥,并且省略会话令牌。AWS 的各种 SDK、aws CLI、
terraform 和 boto3 都会自己去接。扫描器读到那份配置文件,拿到的是一个它调用不了的辅助
程序路径。
就算你还是把那把假的秘密密钥拿走,拿走的也是一件死物。访客端用那个赝品给请求签名,宿主
在出去的路上剥掉签名,再用真密钥重新签一次。任何走其他途径抵达 AWS 的请求,都会以
InvalidSignatureException 失败。F5 的最后一条建议,是把每一份本机机密都当成已泄露并
加以轮换。Bromure 自家文档里对应的那一行,读起来正好相反:因为泄露的只有赝品,真正的
凭据永远不需要轮换。
字典里有一条点名的文件真的值钱:terraform.tfstate。状态文件跟着仓库走,所以决定它
暴露程度的是你的共享文件夹清单。宿主文件夹以 virtiofs 挂载的形式接进工作区,挂在
/home/ubuntu/<basename>,每个工作区上限八个,而那也是虚拟机唯一够得着的 Mac 文件
系统部分。只共享代理正在处理的那个仓库,其他都不共享,那么路径穿越找到的就是一个目录,
而不是一整块磁盘。
今年大多数开发者安全故事描述的都是某样东西抵达:一个包、一份压缩档、一份文档文件。 这里什么都没有抵达。取而代之的是,每个月 32,000 个请求要求一个你亲手启动的进程,把 文件念给一个陌生人听;而结局取决于是哪台机器在跑那个进程,以及它的主目录里放着什么。
把代理的开发服务器放到一台只有你的 Mac 在上面的交换机,并且把它的主目录填满赝品。 安装 Bromure Agentic Coding,然后就让扫描器去问吧。