首页 网络安全 正文

ItzCrazyKns Vane API未授权访问CVE-2026-9371

摘要

栋科技漏洞库关注到 ItzCrazyKns Vane 中存在的 API未授权访问漏洞,该漏洞现在已经被追踪为CVE-2026-9371,CVSS 3.X评分5.6。

Vane 是由用户 ItzCrazyKns 开发的开源 AI 搜索引擎 / 问答引擎,对标 Perplexity AI,主打隐私优先、本地可部署、联网+大模型结合。

一、基本情况

ItzCrazyKns Vane 是开源 AI 搜索引擎,开源免费,基于 Next.js 16、TypeScript、SQLite 和 Node.js 构建,提供LLM对话和搜索功能。

ItzCrazyKns Vane API未授权访问CVE-2026-9371

ItzCrazyKns Vane基于Next.js+TypeScript,前端简洁,后端API开放,默认数据本地处理,支持完全离线/本地模型,搜索记录不上云。

栋科技漏洞库关注到 ItzCrazyKns Vane 中存在的 API未授权访问漏洞,该漏洞现在已经被追踪为CVE-2026-9371,CVSS 3.X评分5.6。

二、漏洞分析

CVE-2026-9371漏洞是位于Vane 1.12.1版本开放全部16个及以上 API 接口中的安全漏洞,源于未设置任何身份认证与权限校验机制。

程序不存在认证中间件、会话校验、接口密钥核验及各类访问控制逻辑,所有接口路由均可直接处理任意网络客户端发来的请求所致。

受影响版本中,src/app/api/config/route.ts 的 GET 和 POST 处理器缺少认证中间件,

任何网络可达客户端可直接访问 /api/config 端点获取完整配置(包括所有 LLM 提供商 API 密钥),或通过 POST 任意修改配置参数。

同样地,/api/chats、/api/providers 等 16+ 个 API 端点均不存在任何认证、授权检查或会话验证。

具体来说,由于Vane是基于Next.js开发的人工智能搜索引擎,后端通过框架路由处理文件`src/app/api/*/route.ts`对外提供REST接口。

所有接口处理请求时,均不会校验请求方身份与访问权限。

(一)程序存在以下缺失项

无认证中间件,项目源码未包含middleware.ts文件

无会话认证体系,不存在登录流程、会话令牌与JWT凭证

接入请求未校验接口密钥

未配置IP白名单与访问频次限制

未设计角色权限管控机制

无用户数据表,SQLite数据库仅存储会话与消息数据,不存在用户相关表单

该程序完全缺失访问控制能力,对所有来源的HTTP请求均无条件信任。

(二)未授权远程攻击者可执行以下操作

读取并篡改全站应用配置,包含第三方接口密钥

查看、清空所有用户聊天记录

向服务器上传任意文件

新增、编辑、删除大语言模型服务商信息

发起对话与检索请求,消耗接口调用额度

借助重连接口劫持在线会话

将检索服务流量劫持至恶意服务器

(三)受影响的终端节点

ItzCrazyKns Vane API未授权访问CVE-2026-9371

(四)受影响代码分析

1、配置端点——无认证保护

文件:src/app/api/config/route.ts

export const GET = async (req: NextRequest) => {
  try {
    const values = configManager.getCurrentConfig();  // No auth check
    const fields = configManager.getUIConfigSections();
    // ... returns full config to any caller
    return NextResponse.json({ values, fields });
  } catch (err) { /* ... */ }
};

export const POST = async (req: NextRequest) => {
  try {
    const body: SaveConfigBody = await req.json();
    // No auth check -- any caller can modify ANY config key
    configManager.updateConfig(body.key, body.value);
    return Response.json({ message: 'Config updated successfully.' }, { status: 200 });
  } catch (err) { /* ... */ }
};

2、聊天记录——数据全量外泄与删除

文件:src/app/api/chats/route.ts

export const GET = async (req: Request) => {
  try {
    let chats = await db.query.chats.findMany();  // No auth check, returns ALL chats
    chats = chats.reverse();
    return Response.json({ chats: chats }, { status: 200 });
  } catch (err) { /* ... */ }
};

文件:src/app/api/chats/[id]/route.ts

export const DELETE = async (req: Request, { params }) => {
  try {
    const { id } = await params;
    // No auth check -- any caller can delete any chat
    await db.delete(chats).where(eq(chats.id, id)).execute();
    await db.delete(messages).where(eq(messages.chatId, id)).execute();
    return Response.json({ message: 'Chat deleted successfully' }, { status: 200 });
  } catch (err) { /* ... */ }
};

3、供应商管理——基础设施接管

文件:src/app/api/propers/route.ts

export const POST = async (req: NextRequest) => {
  try {
    const body = await req.json();
    const { type, name, config } = body;
    // No auth check -- any caller can create providers with arbitrary baseURL
    const registry = new ModelRegistry();
    const newProvider = await registry.addProvider(type, name, config);
    return Response.json({ provider: newProvider }, { status: 200 });
  } catch (err) { /* ... */ }
};

4、文件上传——任意文件处理

文件:src/app/api/uploads/route.ts

export async function POST(req: Request) {
  try {
    const formData = await req.formData();
    const files = formData.getAll('files') as File[];
    // No auth check -- any caller can upload files
    const uploadManager = new UploadManager({ embeddingModel: model });
    const processedFiles = await uploadManager.processFiles(files);
    return NextResponse.json({ files: processedFiles });
  } catch (error) { /* ... */ }
}

(五)会话重新连接--会话劫持

文件:src/app/api/reconnect/[id]/route.ts

export const POST = async (req: Request, { params }) => {
  try {
    const { id } = await params;
    const session = SessionManager.getSession(id);  // No auth -- any session ID
    // ... attaches to the live streaming session
  } catch (err) { /* ... */ }
};

(六)缺少中间件

在项目源代码树的任何级别(src/、src/app/或root)都不存在middleware.ts文件。这确认不存在集中式身份验证或授权层。

(七)攻击流程

                          ATTACKER (Unauthenticated)
                                    |
                    +---------------+----------------+
                    |               |                |
              [Recon Phase]   [Exploit Phase]   [Persistence]
                    |               |                |
                    v               |                |
          GET /api/config           |                |
          (Read full config         |                |
           + all API keys)          |                |
                    |        +------+------+         |
                    |        |      |      |         |
                    v    GET /api/ POST /api/ POST /api/
              Use stolen    chats   config    providers
              API keys on   (Read   (Redirect (Register
              attacker's    all     SearxNG   malicious
              infra         data)   to attk)  provider)
                    |          |       |          |
                    v          v       v          v
              Financial     Data    Search    Full LLM
              loss (quota   theft   MITM      traffic
              abuse)                          interception

   Parallel Destruction:
   DELETE /api/chats/{id}     --> Wipe all chat history
   DELETE /api/providers/{id} --> Disable all LLM providers (DoS)

三、POC概念验证

(一)所有PoC都针对运行在localhost:3001上的实时实例进行了测试和确认。

PoC 1:枚举所有聊天记录(无身份验证)

管理员已设置登录后刷新可查看

观测输出:

{
    "chats": [
        {
            "id": "f5e03fe8cfdf926ffbf1e401446dd7920bacbd7c",
            "title": "1",
            "createdAt": "2026-04-09T03:50:30.828Z",
            "sources": ["web"],
            "files": []
        }
    ]
}

PoC 2:读取聊天详细信息并提取会话ID(无身份验证)

管理员已设置登录后刷新可查看

观测输出:

backendId: e2565fac-36fd-4a67-983a-9c44643d3a08, query: 1

backendId可以与/api/reconnect/[id]一起使用,以劫持活动会话。

PoC 3:创建恶意模型提供者(无身份验证)

管理员已设置登录后刷新可查看

结果:创建一个指向攻击者基础架构的新模型提供程序,无需任何身份验证。

PoC 4:重定向搜索后端(无身份验证)

管理员已设置登录后刷新可查看

观测结果:

{"message":"Config updated successfully."}

已验证:所有后续搜索查询现在都被路由到攻击者的服务器。

PoC 5:删除聊天记录(无身份验证,破坏性)

管理员已设置登录后刷新可查看

结果:从SQLite数据库中永久删除聊天和所有相关消息。

(二)根本原因分析

根本原因是系统在架构层面**完全缺失身份认证与授权机制**:

无身份认证中间件:Next.js 提供了 middleware.ts 请求拦截机制,但项目中未创建该文件。

无单路由权限守卫:16 个以上的接口处理函数中**未包含任何身份认证逻辑**,所有接口都会直接处理请求内容。

无用户模型:应用未设计用户、会话、角色相关概念,SQLite 数据库无用户表。

隐式信任模型:应用设计时默认仅允许本地访问,**未考虑公网暴露场景**(云部署、端口映射、Docker 容器化)。

无深度防御机制:未提供任何二级防护,如限流、跨域限制、CSRF 令牌、IP 白名单等。

(三)修复建议

(1)紧急缓解措施

1、网络隔离:仅绑定 127.0.0.1 本地地址,**禁止暴露到不可信网络**。

2、反向代理认证:部署在 Nginx/Caddy 后方,启用 HTTP 基础认证或 OAuth2 代理认证。

3、防火墙规则:仅允许受信任 IP 访问服务端口。

(2)应用级修复方案

4、实现 Next.js 中间件身份认证:

// src/middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  const token = request.headers.get('Authorization')?.replace('Bearer ', '');
  if (!token || !isValidToken(token)) {
    return NextResponse.json(
      { message: 'Authentication required' },
      { status: 401 }
    );
  }
  return NextResponse.next();
}

export const config = {
  matcher: '/api/:path*',
};

5、添加带会话管理的用户认证机制(如 NextAuth.js / Auth.js)。

6、实现基于角色的访问控制(RBAC),将管理操作(配置、模型服务商)与用户操作(聊天、搜索)分离。

7、在所有接口添加限流机制,尤其是聊天和搜索这类会消耗大语言模型配额的接口。

8、对会修改系统状态的操作(POST、PATCH、DELETE)添加 CSRF 防护。

9、实现审计日志,记录配置修改与管理类操作。

四、影响范围

Vane ≤ 1.12.2

五、修复建议

Vane > 1.12.2

六、参考链接

管理员已设置登录后刷新可查看



扫描二维码,在手机上阅读
评论
更换验证码
友情链接