leofang2007-maker/prompt-audit

GitHub: leofang2007-maker/prompt-audit

自托管的 AI 编程助手提示词审计平台,通过客户端 hook 捕获并记录开发者发送给各类 AI 编码工具的完整提示词内容,帮助合规与安全团队实现跨供应商的统一可见性与数据治理。

Stars: 1 | Forks: 0

# Prompt 审计 [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/leofang2007-maker/prompt-audit/actions/workflows/ci.yml) [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) 你的开发者会将代码、`.env` 文件和上下文粘贴到 **Claude Code、Cursor、GitHub Copilot、 Qoder** 等工具中——而安全/合规团队几乎无法看到*这些提示词(prompt)中到底包含了什么内容*。网络 DLP 只能看到加密的会话;供应商的管理控制台不仅因工具而异、缺乏一致性,而且通常不显示提示词的**内容**。prompt-audit 填补了这一空白:一个轻量级的**客户端 hook** 会捕获每一次提交的提示词,并将其报告给自托管的服务,合规/安全团队可以在此进行搜索、检查和导出。 ![Prompt Audit — 审计控制台](https://static.pigsec.cn/wp-content/uploads/repos/cas/be/be51b6da4210255d51b1a769ca73310ce094aadf8836fdfe65c405fa7044881e.png) *审计控制台:按用户 / 组织 / 仓库 / 关键词 / 时间范围进行过滤,打开任何提示词查看完整内容,并导出为 CSV/JSON。每个组织的管理员只能看到其本组织的提示词。* **用例** - 用于 AI 生成代码的**合规与安全证据**(SOC 2 / GDPR):一条可搜索、可导出的轨迹,记录开发者发送给 AI 编程助手的每一次提示。 - **治理“影子 AI”**:按用户和按组织查看*什么*提示词——以及什么数据——被发送给了 AI 工具。 - **捕获机密/IP 泄露**:对提示词进行全文搜索,以查找 token、密钥或客户数据。 ## 它有何不同 - **在客户端捕获,与工具无关。** 适用于 Claude Code / Cursor / Copilot / Qoder—— 甚至当工具**直接与供应商云通信**时也能生效(模型路径中没有代理,无需提供商密钥)。这是 SIEM/EDR 和网络 DLP 遗漏的“代理层”盲区。 - **内容级别,而不仅仅是使用情况。** 捕获完整的提示词文本,而不仅仅是“谁使用了多少 token”或仓库名称——这已经是大多数供应商控制台能暴露的全部信息了。 - **集中管理所有供应商。** 提供一个跨供应商的统一视图,而不是每个工具都有一个不同的管理面板。 - **自托管——你的提示词永远不会离开你的基础设施。** 没有第三方持有开发者的提示词(这正是其中的敏感数据所要求的)。支持多租户 + Apache-2.0 开源协议。 - **旨在作为赋能工具,而非监控手段。** 数据保留在你的基础设施上;组织管理员只能看到其本组织的数据。(基于角色的访问控制、记录查看原因的管理员视图以及机密/PII 脱敏功能已在[路线图](#roadmap)中——见下文。) 本仓库提供了**完整的两部分**:**服务端**(接收 + 存储 + 审计控制台)和负责捕获每个提示词并报告的 **Qoder 客户端插件**([`clients/qoder/`](clients/qoder/))。 安装插件,运行服务端——即可完成。(任何具有提交前 hook 的工具都可以工作;有关通用报告器和 Claude Code 的集成,请参阅 [`examples/`](examples/)。) ``` AI coding tool (dev machine) Compliance / security team │ client hook │ browser │ POST /api/v1/prompts │ your reverse proxy (TLS) │ Authorization: INGEST_TOKEN (write-only) │ admin session (read-only) ▼ ▼ ┌────────────────── server (Spring Boot) ──────────────────┐ │ / → SPA (React, baked into the jar) /api/* → API │ ← 1 container └──────────────────────────────┬────────────────────────────┘ ▼ MySQL (`promptaudit` DB) ``` **单一容器**:服务端同时提供 SPA(构建好的 React bundle 被打包进了 jar 包的静态资源中)和 API 服务——不需要单独的 web/nginx 进程。将其置于你自己的 TLS 反向代理之后即可。多租户:每个组织都有自己独立的接收 token 和管理员登录凭证,并在各组织之间实行严格的数据隔离。 ## 安全特性(核心重点) 两种**完全独立**的身份验证机制,加上租户隔离: | 受众 | 路由 | 认证 | 权限 | |---|---|---|---| | 组织的客户端 hook | `POST /api/v1/prompts` | 该组织的接收 token | **只写** | | 组织管理员 | `GET /api/v1/prompts[...]`, 导出 | 会话 JWT (role=org, tenant=X) | **只读 — 仅限该组织的数据** | | 平台超级管理员 | + `/api/v1/tenants/*` | 会话 JWT (role=platform) | 管理组织/token/管理员;读取所有数据 | [`server/.../auth/SecurityInterceptor.java`](server/src/main/java/com/gigrt/promptaudit/auth/SecurityInterceptor.java) 中的两项保证: 泄露的接收 token 无法读取任何记录;并且提示词所属的组织是**从接收 token 推导出来的**(被标记为受信任的 `tenant_org_id`),而不是由客户端声称的 `org_id` 决定的—— 因此,机器无法伪造身份去访问另一个组织的数据,并且每次管理员读取操作都会被过滤在其所属的租户内。 ## API | 方法 | 路径 | 认证 | 用途 | |---|---|---|---| | `POST` | `/api/v1/prompts` | 接收 token | 报告提示词。Body (v1.0.2):`{event_id?, timestamp, session_id, user_email, user_name, user_uid, org_id, org_name, repo, branch, cwd, transcript_path, hostname, prompt}`。仅 `prompt` 为必填(否则返回 400);其他所有字段均为可选,并按原样存储(fail-open,缺失 ⇒ null)。→ `200 {"ok":true,"id":"pr_…"}`。**基于 `event_id` 实现幂等**:重复请求(IDE 双重触发/排空重试)将返回原始 id 及 `"deduplicated":true` 标识——不会插入新行。仅记录提示词的**长度**——绝不记录 token 或文本。 | | `POST` | `/api/v1/auth/login` | — | 登录(来自环境变量的平台超级管理员,或来自数据库的组织管理员)→ `{token, profile{role,cap,tenant,org_name}}`(`cap` = `viewer`\|`auditor`)。 | | `POST` | `/api/v1/auth/logout` | 管理员 | 无状态确认(客户端丢弃 token)。 | | `GET` | `/api/v1/prompts` | 管理员 | 经过过滤、分页的列表——**隔离至调用者的租户**(平台管理员可见所有)。参数:`from,to,user_email,org_id,user_uid,repo,session_id,keyword,page,page_size`。 | | `GET` | `/api/v1/prompts/{id}?reason=…` | 管理员 | 完整记录(跨租户 id ⇒ 404)。**viewer** 只能获取元数据 + 脱敏预览(`prompt_hidden`);**auditor**/平台管理员必须提供 `reason`,并且全文展示会被记录访问日志(规范 [0003](docs/specs/0003-anti-surveillance-guardrails.md))。 | | `GET` | `/api/v1/prompts/export?format=csv\|json&reason=…` | auditor | 导出当前(租户范围内)的过滤集。Viewers → 403;必须提供 `reason` 并记录在案。 | | `GET` | `/api/v1/integrity` | 管理员 | 校验防篡改哈希链(规范 [0001](docs/specs/0001-tamper-evident-storage.md>));报告 `ok` 以及第一条被破坏的记录(如果有)。限定在租户范围内。 | | `GET` | `/api/v1/access-log` · `/integrity` | 管理员 | “监视监视者”日志(规范 [0003](docs/specs/0003-anti-surveillance-guardrails.md)):记录每一次全文查看/导出,及其提供的原因——该日志本身也受哈希链保护。限定在租户范围内。 | | `GET` | `/api/v1/transparency` | **公开** | 披露捕获了哪些内容、机密是否已脱敏、管理员访问是否被记录,以及未计算任何生产力评分等信息——方便引导开发者查看。 | | `GET` · `POST` | `/api/v1/coverage` · `/coverage/roster` | 管理员 | 报告覆盖率/盲区检测(规范 [0004](docs/specs/0004-reporting-coverage-gap-detection.md)):对比活跃主机与**已失联**主机,并对照可选的名单检查**从未报告过**的主机。主机粒度;限定在租户范围内。 | | `GET` | `/api/v1/evidence?from=&to=` | auditor | 可用于审计的**证据包**(规范 [0007](docs/specs/0007-audit-ready-kit.md)):完整性 + 访问日志摘要 + 覆盖率 + 脱敏统计 + 计数 + 配置证明,并由 `bundle_hash` 进行锚定。仅包含摘要/哈希值,不包含提示词文本。限定在租户范围内,记录访问日志。 | | `POST` | `/api/v1/tenants/{id}/admins/{aid}/role` | 平台 | 设置组织管理员的能力角色(`viewer`/`auditor`)。 | | `GET`·`POST` | `/api/v1/tenants` · `/{id}/rotate-token` · `DELETE /{id}` | 平台 | 列出/创建组织,轮换/撤销其接收 token。 | | `GET`·`POST` | `/api/v1/tenants/{id}/admins` · `DELETE /{id}/admins/{aid}` | 平台 | 管理组织的管理员登录凭证。 | | `GET`·`POST` | `/api/v1/my/tenant` · `/tenant/rotate-token` | 组织管理员 | 查看/轮换**您自己**组织的接收 token。 | ## 数据模型 `id` · `event_id` (幂等键,UNIQUE) · `timestamp` (客户端事件时间,RFC3339 UTC) · `received_at` (服务器时间) · `session_id` · `user_email` · `user_name` · `user_uid` · `org_id` · `org_name` · `repo` · `branch` · `cwd` · `transcript_path` (报告机器上的绝对路径—— 仅存储,从不获取) · `hostname` · `prompt` (全文) · `prompt_length` · `tenant_org_id` (受信任的所属组织,来自接收 token——隔离键)。 在 `received_at`、`user_email`、`org_id`、`user_uid`、`repo`、`session_id`、`tenant_org_id` 上建有索引; `event_id` 上设有 UNIQUE 约束。此外还有 `tenant`(组织及其 token)和 `admin_user`(组织登录凭证,PBKDF2)表。 ## 快速开始 只需一条命令,零外部依赖(内置了自己的 MySQL): ``` docker compose up --build # → http://localhost:8091 ``` 默认设置(可在 `.env` 中覆盖):管理员 `admin@promptaudit.local` / `changeme`,接收 token 为 `dev-ingest-token`。登录后,在 **Organizations** 下创建一个组织,它将获得自己的接收 token。 ## 本地开发 更快的迭代循环——后端 + 前端分开运行: ``` # terminal 1 — 后端(测试使用内存 H2;运行时,将 DB_* 指向任意 MySQL) cd server DB_HOST=… DB_USER=… DB_PASSWORD=… ADMIN_PASSWORD=changeme INGEST_TOKEN=dev-token \ mvn spring-boot:run # :8080 # terminal 2 — 前端(vite 代理 /api → :8080) cd web && npm install && npm run dev # http://localhost:5173 ``` 试用一下: ``` # 报告 prompt(写入端) curl -X POST http://localhost:8091/api/v1/prompts \ -H "Authorization: Bearer dev-ingest-token" -H "Content-Type: application/json" \ -d '{"timestamp":"2026-07-15T10:00:00Z","user_email":"dev@acme.com","repo":"acme/api","prompt":"refactor the auth module"}' # 然后以 admin@promptaudit.local / 身份登录 http://localhost:8091 并浏览。 ``` 有关将客户端 hook 集成到 Claude Code 或任何工具的方法,请参阅 [`examples/`](examples/)。 ## 项目结构 ``` server/ Spring Boot control plane — ingest + audit API + JWT/ingest auth (plain Spring Boot, Java 8) server/Dockerfile builds web/ and bakes the SPA into the jar → one self-contained image web/ React + Vite + TS audit console — login, list/filter, detail, export clients/ client integrations — clients/qoder/ is the Qoder plugin (UserPromptSubmit hook that reports each prompt, + SessionStart drain-retry for offline queueing) ops/ build.sh / deploy.sh / example reverse-proxy config for production examples/ generic client-hook reference (report_prompt.sh + Claude Code wiring) ``` ## 配置 全部通过环境变量进行配置(参见 [`.env.example`](.env.example)):`DB_*` (MySQL,专用的 `promptaudit` 数据库), `ADMIN_EMAIL` / `ADMIN_PASSWORD` (平台超级管理员引导),`JWT_SECRET`,`INGEST_TOKEN` (可选的全局/引导 token——通常每个组织都会从 Organizations 页面获取自己独立的 token)。 ## 数据与持久化 两个 compose 文件,两种存储模型——按环境选择: | 运行环境 | Compose | 数据库 | 跨重新部署的数据状态 | |-----|---------|----------|-----------------------| | 本地/评估 | `docker-compose.yml` | **内置**自己的 MySQL(命名卷 `promptaudit-db`) | 持久化在卷中;仅在首次 `up` 时为空 | | 生产环境 | `docker-compose.prod.yml` | 连接到**您外部的** MySQL (`DB_*`) | 原封不动——您的数据行保留在您的 MySQL 中 | Schema 在启动时由 Hibernate (`ddl-auto=update`) 根据 JPA 实体自动创建/升级—— **仅为增量更新**:它会添加缺失的表/列,绝不删除或清除数据。因此**部署新镜像不会重置数据库**——现有数据在升级后依然存在。(不附带 `.sql` 迁移脚本;对于更严格的生产环境变更控制,请添加 Flyway/Liquibase。) 无论是仓库还是镜像都不包含数据库或任何数据——仅包含应用程序 + schema 定义(JPA 实体类)。数据库是在运行时通过 `DB_*` 挂载的。 ## 部署 构建一个镜像(`ops/build.sh`),并使用指向您 MySQL 的 `docker-compose.prod.yml` 运行它, 将其置于您自己的 TLS 反向代理之后(`ops/nginx-prompt-audit.site` 中 nginx 配置示例)。 请参阅 [`ops/README.md`](ops/README.md)。 ## 原则——赋能而非监控 Prompt 审计是由安全/合规团队出资采购的,但如果开发者联合抵制,它也会夭折。因此,在这里信任是一种 结构性的属性,而不是一句承诺: - **无生产力评分。** 不计算或暴露任何按开发者个人的评分、排名或绩效指标。现在没有,未来也不会作为隐藏的端点存在。 - **最小权限。** 管理员角色分为 `viewer`(元数据 + 脱敏预览)或 `auditor`(全文)。 新管理员默认为 `viewer`。 - **每次查看均需负责。** 查看完整的提示词文本或导出数据需要提供理由,并记录在受哈希链保护的[访问日志](docs/specs/0003-anti-surveillance-guardrails.md)中——包括 平台超级管理员的查看行为。不存在隐形的超级用户绕过机制。 - **不囤积机密。** 格式正确的机密信息会在[捕获时进行脱敏](docs/specs/0002-secret-pii-redaction.md)。 - **对开发者透明。** 公开的 `/api/v1/transparency` 端点准确披露了捕获的内容以及上述限制。 ## 路线图 优先级取决于安全/合规团队和开发者对 AI 编码工具提出的实际需求 (请参阅支持这些需求的[Reddit调研](docs/research/reddit-2026-07.md)): 每一项都是一个已追踪的 issue——点 👍 或留言以帮助我们确定优先级: - ✅ **[防篡改存储](https://github.com/leofang2007-maker/prompt-audit/issues/1)** *(已交付)* —— 仅追加、受哈希链保护的记录;通过 `GET /api/v1/integrity` 进行验证。设计:[规范 0001](docs/specs/0001-tamper-evident-storage.md)。 - ✅ **[捕获时进行机密/PII 脱敏](https://github.com/leofang2007-maker/prompt-audit/issues/2)** *(已交付)* —— 在提示词被存储或哈希*之前*,掩盖格式正确的机密(密钥/token/私钥/`password=…`),这样您可以在保留证据(数量+类型)的同时不囤积机密本身。默认开启 `REDACTION_MODE=mask`。设计:[规范 0002](docs/specs/0002-secret-pii-redaction.md)。 - ✅ **[反监控护栏](https://github.com/leofang2007-maker/prompt-audit/issues/3)** *(已交付)* —— `viewer`/`auditor` 角色、要求提供原因且受哈希链保护的访问日志(`/api/v1/access-log`)、公开的 `/api/v1/transparency` 披露,以及**无生产力评分**。设计:[规范 0003](docs/specs/0003-anti-surveillance-guardrails.md)。 - ✅ **[报告覆盖率/盲区检测](https://github.com/leofang2007-maker/prompt-audit/issues/4)** *(已交付)* —— 显示曾经报告过但**已失联**的主机,以及(配合预期的名单)**从未报告过**的主机。设计上为主机粒度——关注覆盖率,而非活动监控。对应 API `GET /api/v1/coverage`。设计:[规范 0004](docs/specs/0004-reporting-coverage-gap-detection.md)。 - 🔄 **[更多客户端适配器](https://github.com/leofang2007-maker/prompt-audit/issues/5)** —— **Qoder**(✅ 已在真实部署中验证);**Claude Code / Cursor / Codex / GitHub Copilot**(⚠️ 已根据各工具官方文档的 hook API 构建,尚未进行线上验证)。Copilot 仅限于代理层面(经典的聊天/JetBrains 无法捕获——参见 [`clients/`](clients/README.md))。规范 [0005](docs/specs/0005-claude-code-adapter.md)/[0006](docs/specs/0006-cursor-codex-copilot-adapters.md);[验证状态](clients/README.md)。 - ✅ **[可用于审计的工具包](https://github.com/leofang2007-maker/prompt-audit/issues/6)** *(已交付)* —— [SOC 2 / ISO 27001 控制映射](docs/compliance/) + 由防篡改锚定的**证据包**(`GET /api/v1/evidence`),审计员可以生成、查看和下载。设计:[规范 0007](docs/specs/0007-audit-ready-kit.md)。 - **[SSO/SAML + 更细粒度的 RBAC](https://github.com/leofang2007-maker/prompt-audit/issues/7)**。 希望其中某项早日实现,或者有其他需求?请参阅下方的 **反馈与功能请求**。 ## 反馈与功能请求 有需求、想法,或者遇到 bug?我们希望听到您的声音——路线图由真实的用例驱动。 - 💡 **请求功能** → [提交功能请求](https://github.com/leofang2007-maker/prompt-audit/issues/new?template=feature_request.yml)(请告诉我们问题/用例,而不仅仅是解决方案)。 - 💬 **提问或讨论** → [GitHub Discussions](https://github.com/leofang2007-maker/prompt-audit/discussions)。 - 🐛 **报告 bug** → [提交 bug 报告](https://github.com/leofang2007-maker/prompt-audit/issues/new?template=bug_report.yml)。 - 🔒 **安全问题** → 通过[安全公告](https://github.com/leofang2007-maker/prompt-audit/security/advisories/new)私下报告。
标签:域名枚举, 请求拦截