attestral-labs/attestral

GitHub: attestral-labs/attestral

一款面向 AI agent 与 MCP 服务器的开源安全扫描器,通过构建统一的系统模型来检测跨组件的隐藏安全风险。

Stars: 5 | Forks: 1

# Attestral [![PyPI](https://img.shields.io/pypi/v/attestral)](https://pypi.org/project/attestral/) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/99/993938d8ce5e902ccfb9d6747725c320d855dea3235ed9a304cedf0d94c9321f.svg)](https://github.com/attestral-labs/attestral/actions/workflows/ci.yml) [![Python](https://img.shields.io/pypi/pyversions/attestral)](https://pypi.org/project/attestral/) [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE) **面向 AI agent 和 MCP 服务器的安全扫描器。**

attestral scan flagging an insecure MCP agent config in seconds

你的 agent 拥有 shell、浏览器、你的数据库以及一个 Slack token。每个工具独立存在时都没问题。但把它们放在一起,只需一句注入的指令,就能让你的机密数据泄露出去。Attestral 就是那个能看清*全局*的扫描器。 它会解析你的 MCP 配置、agent 指令、system prompt、工具描述以及**代码中定义的 agent**(LangGraph、CrewAI、OpenAI Agents SDK、原生 Anthropic/MCP 工具定义),构建整个矩阵的单一**系统模型**,并审查那些被其他扫描器直接忽略的 agentic 攻击面:prompt 注入、工具投毒、过度授权、记忆投毒,以及只存在于跨服务器交互中的**致命流程**。一个 shell 工具和一个数据外发工具之间只隔着一句注入指令的距离——无论它们是声明在 `.mcp.json` 中还是作为三个 `@tool` 函数存在,Attestral 都能识别出这种流程。它会在*同一个*图谱中对你的云 (Terraform) 和 Kubernetes 进行建模,因此它能识别出 agent 与其可触及的基础设施之间的信任边界,而不是孤立地看待它们。 它分为三层,并且每个发现都会被标记是由哪一层检测出来的:**确定性规则**(始终开启,无 eval,失败即阻断)、用于检测注入文本的可选**本地 ML 分类器**,以及用于减少误报的可选 **LLM-as-judge**。每个发现都会存入一个**防篡改的 SHA-256 证据链**中,你可以将其交给审计员并进行离线验证。无需账户,无需服务器,无需遥测。 ``` pip install attestral attestral scan ./my-project ``` ## 扫描你已安装的 MCP 服务器 无需仓库。直接审计你的 agent 工具已经连接的 MCP 服务器: ``` attestral scan --local ``` 它会发现并扫描来自 Claude Code(用户作用域、项目 `.mcp.json` 以及 `~/.claude.json` 中当前项目的本地作用域)、Claude Desktop、Cursor、VS Code 和 Windsurf 的配置。它会报告哪些来源被发现或缺失,以及每个来源贡献了多少个服务器,打印出它所审查的 agent 工具攻击面清单,并通过与仓库扫描相同的规则 pipeline 运行所有内容。 ## 一条命令快速开始 ``` attestral init # scaffold CI, pre-commit, a waivers file, and a Claude Code skill attestral scan . # review the current project - prints straight to your terminal ``` `attestral init` 会写入四个引导文件,并且**绝不会覆盖任何已存在的文件**(已存在的文件会被跳过并报告): | 文件 | 作用 | |---|---| | `.github/workflows/attestral.yml` | 在 CI 中拦截每一个 PR,并将发现结果上传到 Security 标签页。 | | `.pre-commit-config.yaml` | 在每次提交时运行 attestral(参见 [pre-commit](#run-attestral-on-every-commit))。 | | `attestral-waivers.yaml` | 用于记录、设置过期时间的豁免配置的模板。 | | `.claude/skills/attestral-review/SKILL.md` | 在 Claude Code 中将 Attestral 变成一种审查条件反射:当你添加或编辑 MCP 服务器、agent prompt 或工具时,它知道该去进行扫描。 | ### 在 Claude Code 中使用 Attestral 也可以作为 Claude Code 插件提供,因此这种审查反射会伴随你跨项目使用: ``` /plugin marketplace add attestral-labs/attestral /plugin install attestral@attestral-labs ``` 当你的 agent 攻击面发生变化(新的 MCP 服务器、工具或 system prompt)时,该插件的 `attestral-review` skill 会运行 `attestral scan`,然后解释发现的问题以及如何对其进行拦截。`attestral init` 会将此 skill 植入到单个仓库中;而该插件使其随处可用。 ### 零配置:直接指向一个仓库 无需模型文件,无需设置。`attestral scan .` 会自动发现仓库中的 Terraform、Kubernetes manifests、`.mcp.json`、agent 指令和 A2A 卡片,并在同一个图谱中对它们进行审查。每次扫描都会以它发现了什么,坦白地说,以及它没有读取什么作为开篇。因此,一个干净的结果读起来就是“干净”,而绝不是“它根本没看”: ``` Reviewed 6 components across 2 source files: 6 agent / MCP surface Design review, not SAST: reads declared config and agent wiring, not arbitrary application logic. ``` ### 终端优先的输出 `attestral scan` 会直接在你的终端打印出带有颜色编码、按严重程度分组的审查结果,并且**默认情况下不向磁盘写入任何内容**——不再会有 `attestral-report.*` 文件乱丢在你的仓库里。你可以使用 `-o`(文件主干名)或 `--format` 明确要求输出报告文件: ``` attestral scan . # print only - nothing is written attestral scan . -o review # write review.md + review.json attestral scan . --format sarif -o out # write out.sarif for GitHub Code Scanning attestral scan . --format aibom -o inv # write inv.cdx.json - a CycloneDX 1.6 AI-BOM attestral scan . --quiet --fail-on high # CI: just the summary + gate line, exit 1 on high+ attestral scan . --baseline attestral-baseline.json # first run records; later runs show only net-new ``` AI-BOM 是与发现结果相对应的清单:扫描中的每一个 MCP 服务器、子 agent、A2A endpoint 和指令表面都会作为一个 CycloneDX 1.6 组件或服务存在——包含锁定的包 purl、能力类别、规范的 manifest 哈希值,以及远程 endpoint 上的 `authenticated` 标志——随时准备提供给目前使用 SBOM 的合规和采购工作流。 `--quiet` 会去掉每个发现结果的详细信息,仅打印摘要和拦截状态(扫描干净时则什么都不打印)。颜色仅在交互式终端中输出,在设置了 `NO_COLOR` 环境变量或输出被管道传输时会被禁用,从而保持 CI 日志和管道输出的整洁。 ### 解释任何规则 ``` attestral explain ATL-103 # title, severity, description, fix, and framework refs ``` 终端输出中的每个发现都带有一个 `run: attestral explain ` 的提示,因此其背后的推理和修复方法只需一条命令即可获取。规则 ID 的匹配不区分大小写。 ## 它能捕获什么(237 条规则包) | 领域 | 示例 | |---|---| | **Agentic / MCP**(OWASP LLM Top 10、MCP 研究、2026 CVE) | 拥有 shell 能力的服务器、宽泛的文件系统根目录、非 TLS 传输、env 中的机密信息、自动安装的包(供应链)、可变的 `@latest` 标签(地毯式抽走/rug-pull)、外部获取/浏览器工具、自动批准的操作、未经身份验证的远程服务器、困惑的代理凭证持有者、已知存在 CVE 的软件包版本(例如 mcp-remote CVE-2025-6514)、agent 自身依赖清单(requirements.txt / pyproject / package.json)中已知存在 CVE 的版本(例如 langchain-core "LangGrinch" CVE-2025-68664)、`.claude/settings.json` 中的 hook 配置注入(CVE-2025-59536) | | **记忆 / 上下文投毒**(OWASP ASI06、agent-security SoK) | 任何人都可写的 agent 指令文件(CLAUDE.md、`.cursorrules`、AGENTS.md),导致任何人都可以重写它们来操纵未来的每次运行;将持久化记忆 / 向量数据库作为记忆投毒目标 | | **Agent skills** (SKILL.md) | 授予 shell 或通配符工具访问权限的、可共享组件中的过度授权 packaged、auto-loaded skills;skill 文本会像任何指令文件一样进行注入评分 | | **ML 层** (`attestral[ml]`) | MCP 工具和服务器描述、system prompt 以及 agent 指令文件中的 prompt 注入 / 越狱文本 | | **AWS**(基于 CIS) | 公开的 S3/RDS/Redshift、`0.0.0.0/0` 安全组、通配符 IAM、未加密的 RDS/EBS/EFS/Neptune、禁用的备份、关闭的 KMS 轮换、公开的 EC2/EKS、CloudTrail 缺失、可变的 ECR 标签、明文 ELB 监听器 | | **Azure**(基于 CIS) | 公开的 blob 访问、非 HTTPS 存储、存储 TLS < 1.2 且无基础设施加密、公开的 SQL、通配符 NSG 规则、关闭 Key Vault 清除保护 / 公开网络访问、未强制执行 SSL 的 Postgres/MySQL、Postgres 灵活服务器公开访问、关闭 TDE 的 SQL 数据库、非 HTTPS-only 的 App Service、VM 密码身份验证、启用本地账户的 AKS | | **GCP**(基于 CIS) | `0.0.0.0/0` 防火墙规则、公开的 Cloud SQL、无 SSL 的 SQL、公开的 bucket IAM (`allUsers`)、关闭统一访问的 bucket、无轮换的 KMS 密钥、Compute cloud-platform 作用域 / IP 转发 / 非 Shielded VM、GKE 遗留 ABAC、非私有节点、非 Shielded 节点、client-cert 身份验证 | | **Kubernetes** (CIS K8s) | 特权容器、权限提升、危险 capabilities、以 root 身份运行、host network/PID、hostPath 挂载、缺少资源限制、可变镜像标签 | | **跨领域 / 致命流程**(矩阵级,只在系统模型中可见) | 致命三要素能力组合(私有数据 + 外发)、作为一种正式的**信息流格属性**(机密性/完整性标签,ATL-217)的相同流程,当你应用建议的缓解措施(外发白名单或人工批准门禁)时该属性会被*清除*,而启发式检测仍然会触发、不安全的数据流(不可信输入 → 代码执行,带有命名的源/汇服务器和污点边)、shell + 网络可达性、跨服务器工具覆盖(工具名称冲突、操纵性描述、服务器身份冲突)、agent 运行时和云之间没有声明的边界控制 | 每个发现都映射到 NIST 800-53、ASVS、SOC 2、CIS (AWS/Azure/GCP/K8s)、OWASP LLM/Agentic 和 MITRE ATLAS 参考。agentic 检查还额外映射到了 [docs/agentic-threat-model.md](docs/agentic-threat-model.md) 中 agent-security SoK (Kim et al. 2026) 的攻击/风险分类法。 **你无法对自己进行评分。** 仓库内的基准测试得分为 116/116,但其标签来自于我们自己的测试夹具。因此,我们还会针对八个已发布的 2025-2026 年 CVE 公告进行衡量,这些公告的标签源自公告本身,而不是我们的输出([`evaluation/external-recall.md`](evaluation/external-recall.md)):这个数值允许低于 100%,并且确实如此,每一个遗漏都被详细列出,并提供了弥补它的具体途径。 ## 扫描的工作原理(pipeline) ``` flowchart TB subgraph ING["1 · Ingest"] TF["Terraform (.tf)
vars · locals · local modules resolved"] --> M K8S["Kubernetes
manifests (.yaml)"] --> M MCP["MCP configs
(mcp.json, JSONC-tolerant)"] --> M SP["System prompts, agent instructions
(CLAUDE.md/.cursorrules), skills (SKILL.md)
+ tool descriptions"] --> M AC["Agent settings + hooks, subagents,
A2A agent cards (.claude/**, .well-known/)"] --> M CODE["Agent code (.py)
@tool functions, Anthropic/MCP tool defs,
LangGraph · CrewAI · OpenAI Agents SDK"] --> M DEP["Dependency manifests
(requirements.txt · pyproject · package.json)
known-CVE version match"] --> M LC["Installed agent configs
(scan --local)"] --> M M["SystemModel
components · edges · trust boundaries"] end M --> L1 subgraph REV["2 · Review (layered, each finding tagged by origin)"] L1["L1 Deterministic rules
237 typed matchers · fail-closed
+ cross-server attack path synthesis
+ cross-repo fleet toxic-flow detection
+ information-flow lattice (IFC labels)
+ OWASP AIVSS agentic risk score
origin: deterministic"] L2["L2 ML classifier (optional)
DeBERTa prompt-injection on agentic surfaces
origin: ml"] L3["L3 LLM (optional)
elicitation + LLM-as-judge verifier
origin: llm"] L1 --> L2 --> L3 end REV --> RS["Reachability-based severity
finding on a walked attack chain:
chain attached · raised one band"] RS --> W["Waivers + inline suppression
documented exceptions · one-line // attestral:ignore"] W --> BL["Baseline
diff-aware: report only net-new findings"] BL --> EV["3 · Evidence
SHA-256 hash chain · verify offline
+ optional Ed25519/DSSE signed head"] EV --> OUT["Output: Terminal (default, writes nothing) · Markdown · JSON · SARIF (Code Scanning) · AI-BOM (CycloneDX 1.6)"] style L1 fill:#0a7d3611,stroke:#0a7d36 style L3 fill:#96222E11,stroke:#96222E ``` | 层级 | 作用 | 可复现? | 成本 | |---|---|---|---| | **L1 确定性规则** | 针对模型的 237 个类型化匹配器,失败即阻断(未知匹配器永远不匹配),加上跨服务器攻击路径合成 | 是,完全可复现 | 免费,离线 | | **L2 ML**(可选) | 对 agentic 文本攻击面(MCP 工具/服务器描述、system prompt)进行 prompt 注入 / 越狱评分。三个层级:零依赖启发式(默认)、ONNX(`attestral[onnx]`,模型级,不需要 torch)或 DeBERTa(`attestral[ml]`) | 固定的模型和版本 | 免费,首次缓存后离线 | | **L3 LLM**(可选) | 探索新的设计威胁,评判者对发现结果进行交叉审查以减少误报 | 判决结果记录在证据链中 | 消耗你的 API key | 每个发现都带有其 `origin`,因此确定性核心永远不会与模型推理混杂在一起。这种分离正是使审查达到审计级别的关键。 **经得起辩护的严重程度。** 当一个发现的组件处于符号遍历显示可达的攻击链上(有途径进入、有途径执行代码、有途径流出)时,该发现会携带该链条,并将其严重性提升一级——但绝不会超过链条本身的严重程度: ``` HIGH (3) ATL-107 MCP server grants outbound network or browser access (mcp_server.web) path: internal chain: web -> ops -> web · this component: entry+impact · raised from medium ``` 提升后的 HIGH 级别附带了证明其合理性的 entry → pivot → impact 路径,因此人们会信任它而不是与之争论。相反的操作是刻意禁止的:脱离所有链条的发现不会被降级,因为缺乏建模路径并不等于安全。 ## 高级功能层(可选) ``` # 对 agentic 文本表面(MCP tool/server 描述和 # system-prompt 文件)进行 ML prompt-injection 扫描。命中结果会被标记为 origin: ml 并汇入相同的 evidence chain。 # 三个层级,通过 --ml-engine(或 ATTESTRAL_ML_ENGINE)进行选择;默认为 auto: # heuristic 零依赖,即时,内置于 core -> attestral scan --ml(无需额外安装) # onnx 通过 onnxruntime 实现模型级 DeBERTa,无需 torch,约 276 MB <- 推荐 # deberta 最重量级,可微调,需拉取 torch(约 700 MB+) # `auto` 优先级:onnx -> deberta -> heuristic。缺少额外依赖绝不会引发错误。 attestral scan ./my-project --ml # zero-install heuristic tier pip install "attestral[onnx]" # add the light, accurate ONNX tier attestral scan ./my-project --ml --ml-engine onnx # weights auto-download once, offline after # 使用自定义或 air-gapped 模型?运行 scripts/export_onnx.py,然后设置 ATTESTRAL_ML_MODEL=/path attestral scan ./my-project --ml --ml-threshold 0.7 # tune sensitivity # 在确定性层之上进行 LLM 威胁引导 export ANTHROPIC_API_KEY=... attestral scan ./my-project --llm # LLM-as-judge:交叉审查发现结果以减少 false positives。 # 判定结果(confirmed / false_positive / needs_review)将被记录在 chain 中。 export ATTESTRAL_JUDGE_API_KEY=... # or reuse ANTHROPIC_API_KEY attestral scan . --judge --judge-panel 3 # 3 judges vote per finding attestral scan . --judge --judge-suppress # auto-waive confident false positives, on the record ``` 评判者永远不会删除发现结果。一个确信的 `false_positive` 会变成一个带有评判者推理过程的、机器生成的豁免:从拦截门禁中隐藏,但仍保留在记录中。 每个发现还带有一个静态的 **confidence**(高/中/低)。根据约定,确定性规则为高——即在良性语料库中误报率为零的结构事实——而 ML 层的置信度则跟踪其。`attestral scan --min-confidence high` 仅保留那个对 CI 安全的集合,并报告它丢弃了什么,这样你就可以基于不可能出错的发现来中断构建,而将概率性的发现留给人工处理。对于个别的误报,配置中一行简单的 `// attestral:ignore ATL-xxx reason: ...` 标记就可以将其就地豁免(保留在证据链中,而不是被隐藏)。良性的零误报承诺是一个受控测试,而非空头支票;参见 [`docs/false-positive-budget.md`](docs/false-positive-budget.md)。 ### 调优 / 训练 ML 层 ML 层开箱即用,指向一个已经针对 prompt 注入进行过微调的 DeBERTa 分类器,因此请**从 zero-shot 开始**(`--ml`,无需训练)。如果你需要使其适应你自己的攻击面,可以攀登三个层级——按原样使用、在你的标记数据上校准 `--ml-threshold`,然后仅在有差距时进行微调。一个可运行的方案(微调 + 阈值校准脚本、数据格式以及从哪里获取训练数据)位于 [`training/`](training/README.md) 中。 ## 基准与豁免 真实的仓库一开始总会有发现结果。豁免可以接受已知的风险并保持拦截门禁通过,同时不隐藏任何东西:被豁免的发现连同其理由一起保留在证据链中,并成为 SARIF 中的一个抑制(GitHub 会将其显示为已驳回,而不是未解决)。 ``` # attestral-waivers.yaml(在扫描根目录自动发现) waivers: - rule: ATL-005 component: aws_db_instance.app # or "*" for every component reason: Encryption enforced at the storage layer; tracked in SEC-1234. expires: 2026-12-31 # optional ``` 故障安全:没有 `reason` 的豁免会被忽略,过期的豁免会停止抑制。一个发现只能通过一个当前的、有充分理由的例外来被静默。 ### 接受风险本身就是审计记录 推荐使用 `attestral accept` 而不是手动编辑 YAML——它会写入带有来源信息和内容锁定的豁免: ``` # 一行内容,从扫描输出中的发现结果复制而来 attestral accept . ATL-104 mcp_server.jira -r "Secrets rotated nightly; tracked in SEC-1234." --expires 2026-12-31 ``` 记录的条目说明了**谁**接受了风险(你的 git 身份)、**何时**、**为什么**以及接受了**什么**——即在接受时对规则、组件、严重性和可达链进行哈希处理的 `finding_sha256` 锁定。被抑制的发现将该来源信息带入证据链,因此审计员可以直接从记录中读出“该工程师在此日期以该理由接受了此风险”。 这个锁定是保持接受行为诚实的关键:如果风险本身发生变化——一波规则重新评估了该发现,或者一个新的工具完成了一条穿过该组件的攻击链并且可达性提高了其严重程度——锁定就会停止匹配,扫描会报告该接受已过期,并且该发现会重新出现,直到有人重新接受*当前*的风险。你接受的是一个 medium 级别风险;你并没有接受它演变成的 high 级别风险。 ## 跨越仓库的流程:`attestral fleet` Agentic 风险存在于*集成*之中。位于一个仓库中的 shell 工具和位于另一个仓库中的不可信输入工具,各自独立看都没问题;但结合起来它们就构成了一条攻击链。任何单个仓库扫描器都看不到这一点,因为每个仓库在隔离状态下都是干净的。`attestral fleet` 将几个仓库建模为**一个**系统: ``` attestral fleet ./data-agent ./ops-agent ./notify-agent ``` ``` Fleet: 3 repos data-agent 2 components · reach: network, saas_data ops-agent 1 components · reach: shell notify-agent 1 components · reach: messaging cross-repo chain: entry [data-agent] -> pivot [ops-agent] -> impact [notify-agent] ``` 它将每个 repo 合并到一个图谱中(用其所在的 repo 标记每个组件),然后对这个联合体进行完整的审查。当整个矩阵的组合能力完成了一条**没有任何单个 repo 能够单独完成**的攻击链时,它会触发 **ATL-213**,并指出哪个 repo 提供了入口、跳板和数据外发途径。可达性提升也随之而来:一个 repo 中的 medium 发现被提升为 high,因为*另一个* repo 才是完成其链条的关键。这就是单文件扫描器在结构上无法回答的问题,这也正是构建系统模型的意义所在。 ## 超越发现:证明它、执行它、验证它 扫描器止步于发现列表。Attestral 将审查过的设计转化为防篡改的记录和运行时策略:这种深度使审查达到了审计级别,也是它无法被轻易克隆的原因。为设计作证,证明记录未被篡改,将其编译为默认拒绝的运行时策略,并检测运行的内容何时偏离了审查过的内容。整个闭环离线运行,在笔记本电脑上,免费。 ### 完整性,以及现在的真实性 SHA-256 链是**防篡改**的:编辑任何过去的发现,后面的每个哈希值和 head 都会停止匹配。就其本身而言,这只能证明链条在内部是一致的,而不能证明它就是*你*封存的那个链条,攻击者完全可以编辑一个发现,重新计算整个链条和一个新的 head,而 `verify` 仍然会显示 VALID。`attestral sign` 通过**在 DSSE 信封中封装对 head 的 Ed25519 签名**(Sigstore 和 in-toto 使用的是同一个信封)解决了这个问题。现在 `attestral verify --public-key` 会同时检查两者:完整性(没有任何条目被篡改)*以及*真实性(这是密钥持有者封存的链条,而不是重新计算出来的伪造品)。签名需要 `attestral[sign]` 额外依赖;而完整性检查仍然可以在零依赖下运行。 ### 一图胜千言的闭环 ``` flowchart LR A["attestral scan
attest"] --> B["attestral verify
prove"] A --> R["attestral remediate
concrete source edit"] A --> F["attestral fix
compile-the-fix"] A --> C["attestral compile
enforce"] C --> D["attestral drift
detect"] D -->|"design changed?
re-attest"| A A --> V["attestral validate
show the path is reachable"] style A fill:#96222E,color:#fff style B fill:#1F6A4A,color:#fff style F fill:#96222E11,stroke:#96222E style V fill:#96222E11,stroke:#96222E ``` 有两条命令从两端回答了“那我该怎么处理这个发现结果”。`attestral remediate` 会读取规则本身的匹配器和组件的真实值,并打印出需要做出的**具体源码编辑**:需要翻转的布尔标志(`set publicly_accessible = false`)、需要替换的错误值(`http://… -> https://…`)、需要添加的、与其所在文件绑定的控制措施。`attestral fix` 则编译出确切的、**可执行的控制措施**来关闭该发现,绑定到审查的链 head,并给出一个验证结论:一个矩阵级别的发现通过在没有该隔离能力的情况下重新合成模型(`re-synthesized`)来证明已被关闭,而单个服务器级别的发现则获得在代理处管理它的 mcp-guard 约束(`enforced-at-proxy`)。一个*同时也是*可执行运行时控制措施的修复方案,正是 attest-compile-drift(作证-编译-偏移检测)闭环的回报,也是 linter 在结构上无法提供的东西。 ### 四大命令 ``` flowchart LR subgraph scan["attestral scan"] s1["Terraform + MCP"] --> s2["findings + evidence chain
md / json / sarif"] end subgraph verify["attestral verify"] v1["report.json"] --> v2["VALID / INVALID
(offline)"] end subgraph compile["attestral compile"] c1["attested model"] --> c2["default-deny policy
tool manifest hashes pinned,
bound to chain head"] c2 --> c3["narrowing check (--against)
a re-attestation must not widen
the reviewed capability envelope"] end subgraph drift["attestral drift"] d1["policy + telemetry"] --> d2["drift findings
rug-pulls (DRF-005),
loop / volume budgets (DRF-006/007)"] end subgraph memory["attestral memory"] m1["memory store + keyring"] --> m2["signed-provenance audit
relabelled / tampered / unsigned
trust claims (MEM-001/002/003)"] end ``` ``` # SCAN:审查项目(自动发现 Terraform + MCP configs) attestral scan ./my-project --format both # md + json attestral scan . --fail-on high # CI gate: exit 1 on high/critical attestral scan . --min-confidence high --fail-on high # CI-safe set only: structural, 0-FP-on-benign attestral scan . --format sarif -o attestral # SARIF -> GitHub Security tab + PR annotations # VERIFY:证明报告未被篡改(无需网络,无需服务器) attestral verify review.json # SIGN:使 chain 获得认证,而不仅仅是具备防篡改能力(Ed25519 / DSSE) attestral sign --gen-key reviewer # one-time: a keypair attestral sign review.json --key reviewer.key --signer "Ada L" attestral verify review.json --public-key reviewer.pub # checks integrity AND authenticity # COMPILE:将已认证的设计转化为 default-deny mcp-guard policy attestral compile ./my-project -o policy.yaml # 并验证后续设计是否依然缩小了已审查的设计范围(若发生扩大则失败) attestral compile ./my-project --against policy.yaml # DRIFT:将 runtime telemetry 与已认证的设计进行 diff attestral drift policy.yaml events.jsonl --fail-on-drift # MEMORY:通过签名将 agent-memory 条目的信任标签与其内容绑定, # 从而使被重新标记或篡改的条目能够通过加密方式被捕获(而非凭侥幸) attestral memory sign --content "..." --label trusted --writer alice --key alice.key -o mem.jsonl attestral memory verify mem.jsonl --keyring writers.yaml --fail-on-untrusted # VALIDATE:证明组装而成的 attack paths 是否真正成立 # (tier 0:对模型的 edges 进行 symbolic walk,无需执行,无需网络) attestral validate ./my-project attestral validate ./my-project -o proof --fail-on-reachable # write proof.md + chain, gate CI # FLEET:将多个 repos 建模为一个 agent fleet,并查找跨它们的 flows attestral fleet ./repo-a ./repo-b ./repo-c # ATL-213: cross-repo toxic flow ``` ### 安装并运行整个闭环(60 秒) ``` pip install attestral attestral scan examples/demo-project -o review # attest -> review.md + review.json attestral verify review.json # prove -> chain VALID attestral remediate examples/demo-project # remediate -> concrete source edit per finding attestral fix examples/demo-project # fix -> enforceable control per finding attestral compile examples/demo-project -o policy.yaml # enforce -> default-deny policy attestral drift policy.yaml examples/demo-project/runtime-events.jsonl --fail-on-drift # detect ``` ## 真实世界基准测试 在 [TerraGoat](https://github.com/bridgecrewio/terragoat)(Bridgecrew 的刻意设计的易受攻击的 Terraform)上运行,在规则包增长的过程中,针对同一个 repo 进行测试(该包目前是 **237 条规则**;此表显示了历史进展,而不是当前的包大小): | | TerraGoat AWS | TerraGoat Azure | TerraGoat GCP | 独立规则 | |---|---|---|---|---| | v0.4.0 (10 条规则) | 3 | - | - | 3 | | v0.6.0 (57 条规则) | 7 | 2 | 3 | 12 | | v0.9.0 (169 条规则) | **8** | **3** | **5** | **16** | 该 pipeline(摄取、证据链、防篡改检测、门禁、SARIF)已在真实代码上得到验证。一个诚实的警告是:TerraGoat 大量依赖 Terraform 变量和模块,而 Attestral 的 HCL 解析器尚未评估跨变量插值,因此 TerraGoat 的一大堆错误配置隐藏在扫描器目前还无法看透的 `var.` 引用后面。因此,TerraGoat 的数字是一个受限于 HCL 解析深度的**下限**,而不是对 163 条规则的云规则包覆盖范围的衡量。更深层次的 HCL 解析已列入路线图;当它落地时,这些数字将会在不增加任何规则的情况下发生飞跃。 ## 它做不到的事情 一个你可以信任的工具,应该坦诚面对自己的边界。Attestral 是一个**设计审查工具,而不是 SAST 工具**:它读取已声明的攻击面(配置、agent 连线、prompt、IaC),并基于系统模型进行推理,但它不读取工具实现的内部逻辑,不针对你的在线 agent 执行任何操作,也不证明可利用性(可达路径是必要条件,而非充分条件)。它也有已知的盲点:HCL 跨变量解析深度、粗略的能力分类、概率性的 ML 层,以及需要可识别框架的 agent 代码摄取。包括我们自身的检测在面对自适应攻击时会哪里失效的完整列表,请参见 [`docs/limitations.md`](docs/limitations.md)。我们宁愿陈述这些限制,也不愿暗示我们拥有实际上并不具备的覆盖能力。 ## 在 CI 中使用 ``` # .github/workflows/attestral.yml name: attestral on: [pull_request] permissions: contents: read security-events: write # to upload to the Security tab jobs: design-review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: { python-version: "3.12" } - run: pip install "attestral[terraform]" # Inline annotations on the offending line, via GitHub code scanning. - run: attestral scan . --format sarif -o attestral - uses: github/codeql-action/upload-sarif@v3 with: { sarif_file: attestral.sarif } # A clean job summary rendering the reachable attack paths and the # findings this PR introduced (commit attestral-baseline.json first). - run: attestral scan . --baseline attestral-baseline.json --format md-summary -o attestral - run: cat attestral.summary.md >> "$GITHUB_STEP_SUMMARY" # Hard gate: fail only on net-new high/critical (auto-uses attestral-waivers.yaml). - run: attestral scan . --baseline attestral-baseline.json --fail-on high --quiet ``` 该操作会做三件普通通过检查做不到的事情:SARIF 会将每个发现内嵌显示在出问题的代码行上,job summary 会渲染出可达的 **entry → pivot → impact** 路径,这样审查者看到的就是整个故事而不是一个列表,而 `--baseline` 只针对**全新增加**的发现进行门禁拦截,这样存量 repo 在引入时就不会因为第一天的历史债务而失败。`attestral init` 脚手架正是为此而设计的;现成的工作流也位于 `examples/github-actions/`。 ## 在每次提交时运行 attestral ``` pip install pre-commit ``` 添加到 `.pre-commit-config.yaml` 中: ``` repos: - repo: https://github.com/attestral-labs/attestral rev: v0.17.0 hooks: - id: attestral # gate infra/agent config in this repo - id: attestral-local # optional: audit installed MCP servers ``` 然后运行 `pre-commit install`。详情请参见 `examples/pre-commit/`。 ## 编写自定义规则 规则是带有结构化匹配器的 YAML。任何地方都没有 `eval`,并且未知的匹配器会失败即阻断(永远不匹配)。 ``` rules: - id: ORG-001 title: Internal load balancer missing auth attribute severity: high target: aws_lb # component type prefix, or "model" match: { attr_missing: auth } description: ... recommendation: ... frameworks: ["NIST AC-3", "SOC2 CC6.1"] ``` ``` python -c "from attestral.rules import RuleEngine; RuleEngine(['org_rules.yaml'])" ``` ## 开发 ``` pip install -e ".[dev,terraform,llm]" # add ,ml for the DeBERTa layer (pulls torch) pytest -q # offline suite; the live judge test skips without a key ruff check attestral tests ``` 要运行实时的评判者测试,请设置 `ATTESTRAL_JUDGE_API_KEY`(或 `ANTHROPIC_API_KEY`)并重新运行 `pytest -q`。 ### 变更如何发布 ``` flowchart LR subgraph inner["inner loop (local)"] E["edit code / rules / ingesters"] --> T["pytest -q · ruff"] T --> S["attestral scan examples/*
(eyeball real findings)"] S --> E end S --> PR["pull request"] PR --> CI["CI: lint + tests on 3.10 / 3.12
+ docs-sync gate"] CI --> REV["CODEOWNERS review · CLA signed"] REV --> MAIN["main (protected: no force push,
required checks)"] MAIN --> TAG["tag vX.Y.Z + CHANGELOG entry"] TAG --> PUB["publish.yml → PyPI
(Trusted Publishing)"] ``` **docs-sync 门禁** (`tests/test_docs_sync.py`) 保证了本 README 的诚实:当一个没有任何图表显示的 pipeline 模块存在时、当一个 CLI 命令未被记录时,或者当包版本没有 `CHANGELOG.md` 条目时,它就会失败。如果你添加了一个阶段,请把它画出来——否则测试套件将不会通过。 ## License Apache 2.0。
标签:AI安全, Chat Copilot, CISA项目, DLL 劫持, MCP服务器, Python, StruQ, 云安全监控, 图数据库, 大语言模型, 子域名突变, 无后门, 逆向工具, 静态分析