Skip to content

Conversation

@Libres-coder
Copy link
Contributor

@Libres-coder Libres-coder commented Oct 23, 2025

Ⅰ. Describe what this PR did

This PR implements the OWASP A2AS Framework as a standalone WASM plugin (ai-a2as) to provide defense-in-depth protection against prompt injection attacks in AI/LLM applications.

BASIC Security Model (5 Components):

  1. Behavior Certificates: Gateway-level tool call permission enforcement
  2. Authenticated Prompts: Dual-mode signature verification (simple HMAC-SHA256 + full RFC 9421)
  3. Security Boundaries: Wrap untrusted input with XML-style tags (<a2as:user>, <a2as:tool>)
  4. In-context Defenses: Inject meta-security instructions into context window
  5. Codified Policies: Business rules and compliance requirements injection

Key Features:

  • Per-Consumer Configuration via X-Mse-Consumer header
  • 6 Prometheus metrics for observability
  • Multi-protocol support (OpenAI/Claude, streaming/non-streaming)
  • No breaking changes (standalone plugin, AUTHN phase, priority 200)

Ⅱ. Does this pull request fix one issue?

#3020

Reference: https://owasp.org/www-project-a2as/


Ⅲ. Why don't you add test cases (unit test/integration test)?

Test coverage is included:

  • Unit Tests: 10 test suites, 41 sub-tests in main_test.go (100% pass)
  • Test Execution: go test -v . (0.045s)

Ⅳ. Describe how to verify it

Build and Test

cd plugins/wasm-go/extensions/ai-a2as
go test -v .     # Run tests
make build       # Build WASM
1761246089500

Basic Configuration

securityBoundaries:
  enabled: true
  wrapUserMessages: true
inContextDefenses:
  enabled: true
  position: as_system
authenticatedPrompts:
  enabled: true
  mode: simple
  sharedSecret: "your-secret"

Verify Metrics

Check Prometheus endpoint for: a2as_requests_total, a2as_signature_verification_failed, a2as_tool_call_denied, etc.


Ⅴ. Special notes for reviews

Architecture:

  • Standalone plugin (not extending ai-proxy) for modularity and single responsibility
  • Execution phase: AUTHN at priority 200 (runs after auth, before ai-proxy)
  • Dual-mode signatures: simple HMAC for compatibility + full RFC 9421 for standards compliance

Review Focus:

  • Plugin metadata (@Phase, @Priority) correctness
  • Signature verification logic (both simple and RFC 9421 modes)
  • Per-consumer configuration merging
  • RFC 9421 compliance (signature base string, component parsing, timestamp validation)

References:

Files Changed:

  • 9 new files in plugins/wasm-go/extensions/ai-a2as/
  • Core: config.go (434L), main.go (396L), rfc9421.go (334L), main_test.go (553L)
  • Build: Makefile, VERSION (1.1.0), go.mod, go.sum
  • Docs: README.md, README_EN.md
1761246089510

@lingma-agents
Copy link

lingma-agents bot commented Oct 23, 2025

实现 OWASP A2AS 框架的 AI 安全 WASM 插件

变更概述
  • 新功能
    • 实现了基于 OWASP A2AS 框架的独立 WASM 插件 ai-a2as,用于防御 AI/LLM 应用中的提示注入攻击。
    • 实现了 BASIC 安全模型的五个核心组件:
      • Behavior Certificates (行为证书): 在网关层实施工具调用权限控制。
      • Authenticated Prompts (认证提示): 支持双模式签名验证(简化 HMAC-SHA256 + RFC 9421 标准)。
      • Security Boundaries (安全边界): 使用 XML 风格标签包裹不可信输入(<a2as:user><a2as:tool>)。
      • In-context Defenses (上下文防御): 向上下文窗口注入元安全指令。
      • Codified Policies (编码策略): 注入业务规则和合规要求。
    • 支持基于 X-Mse-Consumer 请求头的消费者特定配置,实现差异化安全策略。
    • 提供 6 个 Prometheus 指标用于监控和可观测性。
    • 支持 OpenAI 和 Claude 协议,兼容流式和非流式请求。
  • 安全增强
    • 通过签名验证、权限控制和输入包裹等机制,构建深度防御体系。
    • 强制执行工具调用权限,防止越权操作。
    • 使用内容摘要(SHA-256)增强标签安全性。
    • 通过签名验证确保请求完整性和可追溯性。
  • 配置调整
    • 插件在 AUTHN 阶段以优先级 200 执行,确保在 ai-proxy 之前进行安全处理。
    • 插件配置项丰富,支持对各安全组件的细粒度控制。
    • 支持全局配置和消费者特定配置的合并。
  • 文档
    • 提供了详细的中文和英文 README 文档,涵盖功能说明、配置字段、使用示例、工作原理、安全优势、集成方式、性能影响、故障排除和未来计划。
  • 测试更新
    • 包含完整的单元测试,覆盖所有核心功能,确保代码质量。
变更文件
文件路径 变更说明
plugins/​wasm-go/​extensions/​ai-a2as/​Makefile 定义了使用 tinygo 构建 WASM 插件的目标。
plugins/​wasm-go/​extensions/​ai-a2as/​README.​md 提供了插件的详细中文文档,包括功能说明、配置字段、使用示例、工作原理、安全优势、集成方式、性能影响、故障排除和未来计划。
plugins/​wasm-go/​extensions/​ai-a2as/​README_​EN.​md 提供了插件的详细英文文档,内容与中文文档对应。
plugins/​wasm-go/​extensions/​ai-a2as/​config.​go 定义了插件的配置结构体,包括 A2ASConfig、ConsumerA2ASConfig 及其子组件,并实现了配置解析、验证和消费者配置合并逻辑。
plugins/​wasm-go/​extensions/​ai-a2as/​go.​mod 定义了插件的 Go 模块依赖。
plugins/​wasm-go/​extensions/​ai-a2as/​go.​sum 记录了插件依赖模块的校验和。
plugins/​wasm-go/​extensions/​ai-a2as/​main.​go 实现了插件的核心逻辑,包括请求处理、安全边界应用、上下文防御注入、编码策略注入、行为证书验证和认证提示验证。
plugins/​wasm-go/​extensions/​ai-a2as/​main_​test.​go 包含了插件的单元测试,覆盖了配置解析、安全边界、上下文防御、编码策略、行为证书和认证提示等核心功能。
plugins/​wasm-go/​extensions/​ai-a2as/​rfc9421.​go 实现了 RFC 9421 HTTP 消息签名的相关功能,包括签名输入构建、参数解析和验证逻辑。
plugins/​wasm-go/​extensions/​ai-a2as/​VERSION 定义了插件的版本号为 1.0.0。
时序图
sequenceDiagram
    participant Client
    participant AuthPlugin
    participant A2ASPlugin
    participant AIProxy
    participant LLM

    Client->>AuthPlugin: 发送请求
    AuthPlugin->>A2ASPlugin: 设置 X-Mse-Consumer 头
    A2ASPlugin->>A2ASPlugin: 读取配置并合并消费者配置
    A2ASPlugin->>A2ASPlugin: [Authenticated Prompts] 验证请求签名
    A2ASPlugin->>A2ASPlugin: [Behavior Certificates] 检查工具调用权限
    A2ASPlugin->>A2ASPlugin: [In-context Defenses] 注入安全指令
    A2ASPlugin->>A2ASPlugin: [Codified Policies] 注入业务策略
    A2ASPlugin->>A2ASPlugin: [Security Boundaries] 用标签包裹用户输入和工具输出
    A2ASPlugin->>AIProxy: 转发处理后的请求
    AIProxy->>LLM: 调用 LLM
    LLM-->>AIProxy: 返回响应
    AIProxy-->>Client: 返回响应
Loading

💡 小贴士

与 lingma-agents 交流的方式

📜 直接回复评论
直接回复本条评论,lingma-agents 将自动处理您的请求。例如:

  • 在当前代码中添加详细的注释说明。

  • 请详细介绍一下你说的 LRU 改造方案,并使用伪代码加以说明。

📜 在代码行处标记
在文件的特定位置创建评论并 @lingma-agents。例如:

  • @lingma-agents 分析这个方法的性能瓶颈并提供优化建议。

  • @lingma-agents 对这个方法生成优化代码。

📜 在讨论中提问
在任何讨论中 @lingma-agents 来获取帮助。例如:

  • @lingma-agents 请总结上述讨论并提出解决方案。

  • @lingma-agents 请根据讨论内容生成优化代码。

Copy link

@lingma-agents lingma-agents bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔎 代码评审报告

🎯 评审意见概览
严重度 数量 说明
🔴 Blocker 0 阻断性问题,需立即修复。例如:系统崩溃、关键功能不可用或严重安全漏洞。
🟠 Critical 1 严重问题,高优先级修复。例如:核心功能异常或性能瓶颈影响用户体验。
🟡 Major 2 主要问题,建议修复。例如:非核心功能缺陷或代码维护性较差。
🟢 Minor 1 次要问题,酬情优化。例如:代码格式不规范或注释缺失。

总计: 4 个问题

📋 评审意见详情
💡 代码实现建议
以下是文件级别的代码建议,聚焦于代码的可读性、可维护性和潜在问题。
🔹 plugins/wasm-go/extensions/ai-a2as/config.go (1 💬)
🔹 plugins/wasm-go/extensions/ai-a2as/main.go (3 💬)
🚀 架构设计建议
以下是对代码架构和设计的综合分析,聚焦于跨文件交互、系统一致性和潜在优化空间。
🔍1. 架构一致性问题:插件执行阶段与预期不符

根据 README 文档描述,插件应在 AUTHN 阶段执行,优先级为 200。然而,config.go 文件中的注释表明插件可能在其他阶段运行。这种不一致可能导致插件无法按预期顺序执行,影响安全策略的有效性。需要确认插件实际执行阶段,并更新文档或代码以保持一致。

📌 关键代码

插件执行阶段:`AUTHN`(认证阶段,在 ai-proxy 之前执行)  
插件执行优先级:`200`
// @Name ai-a2as
// @Category ai
// @Phase AUTHN
// @Priority 200
// @Title zh-CN AI Agent-to-Agent 安全
// @Title en-US AI Agent-to-Agent Security
// @Description zh-CN 实现 OWASP A2AS 框架,为 AI 应用提供深度防御,防范提示注入攻击
// @Description en-US Implements OWASP A2AS framework to provide defense in depth for AI applications against prompt injection attacks

⚠️ 潜在风险

插件执行顺序错误可能导致安全策略失效,使系统易受提示注入攻击。

🔍2. 跨文件问题:消费者特定配置合并逻辑不完整

虽然 config.go 中实现了 MergeConsumerConfig 方法来合并消费者特定配置,但该方法仅替换了整个配置对象,而非逐字段合并。这可能导致部分配置丢失或覆盖不当。此外,README 中提到的配置合并规则并未在代码中完全体现。建议完善合并逻辑,确保消费者特定配置能够正确地覆盖全局配置。

📌 关键代码

func (c *A2ASConfig) MergeConsumerConfig(consumerName string) A2ASConfig {
	if consumerName == "" || len(c.ConsumerConfigs) == 0 {
		return *c
	}

	consumerConfig, exists := c.ConsumerConfigs[consumerName]
	if !exists {
		return *c
	}

	merged := *c

	if consumerConfig.SecurityBoundaries != nil {
		merged.SecurityBoundaries = *consumerConfig.SecurityBoundaries
	}

	if consumerConfig.InContextDefenses != nil {
		merged.InContextDefenses = *consumerConfig.InContextDefenses
	}

	if consumerConfig.BehaviorCertificates != nil {
		merged.BehaviorCertificates = *consumerConfig.BehaviorCertificates
	}

	if consumerConfig.CodifiedPolicies != nil {
		merged.CodifiedPolicies = *consumerConfig.CodifiedPolicies
	}

	return merged
}
**配置合并规则**1. 如果请求包含 `X-Mse-Consumer` 头,插件会查找对应的消费者配置
2. 消费者特定配置会覆盖全局配置(仅覆盖已设置的字段)
3. 如果消费者没有特定配置,使用全局配置

⚠️ 潜在风险

配置合并错误可能导致某些安全策略未正确应用,降低系统的安全性。

🔍3. 技术债务:签名验证功能未完全实现 RFC 9421 标准

尽管 README 和代码中提到了 RFC 9421 签名验证,但当前实现仅为简化版 HMAC-SHA256 验证。完整的 RFC 9421 实现在未来版本中计划提供。目前的实现缺乏对签名参数解析、时间戳和 nonce 验证等功能的支持,存在潜在的安全隐患。建议尽快完成 RFC 9421 的完整实现,以提高签名验证的安全性和可靠性。

📌 关键代码

> **版本说明**: v1.0.0 实现了基于 HMAC-SHA256 的简化签名验证。完整的 RFC 9421 实现将在未来版本中提供。
type AuthenticatedPromptsConfig struct {
	// @Title zh-CN 启用签名验证
	// @Description zh-CN 是否启用 RFC 9421 HTTP 消息签名验证
	Enabled bool `json:"enabled"`

	// @Title zh-CN 签名模式
	// @Description zh-CN 签名验证模式:simple(简化HMAC,默认)或 rfc9421(完整RFC 9421标准)
	Mode string `json:"mode"`

	// @Title zh-CN 签名头名称
	// @Description zh-CN HTTP 签名头的名称
	SignatureHeader string `json:"signatureHeader"`

	// @Title zh-CN 共享密钥
	// @Description zh-CN 用于 HMAC 签名验证的共享密钥(base64编码)
	SharedSecret string `json:"sharedSecret"`

	// @Title zh-CN 签名算法
	// @Description zh-CN 签名算法:hmac-sha256(默认)
	Algorithm string `json:"algorithm"`

	// @Title zh-CN 允许的时钟偏差
	// @Description zh-CN 允许的时钟偏差(秒),默认300秒
	ClockSkew int `json:"clockSkew"`

	// @Title zh-CN 允许无签名请求
	// @Description zh-CN 当设置为 true 时,允许没有签名的请求通过;为 false 时,缺少签名的请求将被拒绝
	AllowUnsigned bool `json:"allowUnsigned"`

	// @Title zh-CN RFC 9421 特定配置
	// @Description zh-CN RFC 9421 完整模式的特定配置项
	RFC9421 RFC9421Config `json:"rfc9421,omitempty"`
}

⚠️ 潜在风险

签名验证机制不够健壮,容易受到中间人攻击或重放攻击,影响系统的整体安全性。

🔍4. 可维护性问题:文档和代码中的配置字段描述不一致

README 和 config.go 中对于某些配置字段的描述存在差异。例如,AuthenticatedPromptsConfig 中的 SharedSecret 字段在 README 中标记为条件必填,而在 config.go 的注释中则没有明确指出这一点。这种不一致增加了理解和维护配置的难度,可能导致配置错误。建议统一文档和代码中的字段描述,确保一致性。

📌 关键代码

| `authenticatedPrompts.sharedSecret` | string | 条件必填* | - | HMAC 共享密钥(支持 base64 或原始字符串) |
// @Title zh-CN 共享密钥
	// @Description zh-CN 用于 HMAC 签名验证的共享密钥(base64编码)
	SharedSecret string `json:"sharedSecret"`

⚠️ 潜在风险

配置理解困难,导致错误配置,进而影响插件的功能和安全性。

审查详情
📒 文件清单 (9 个文件)
新增: 9 个文件

✅ 新增文件:

  • plugins/wasm-go/extensions/ai-a2as/Makefile
  • plugins/wasm-go/extensions/ai-a2as/README.md
  • plugins/wasm-go/extensions/ai-a2as/README_EN.md
  • plugins/wasm-go/extensions/ai-a2as/config.go
  • plugins/wasm-go/extensions/ai-a2as/go.mod
  • plugins/wasm-go/extensions/ai-a2as/go.sum
  • plugins/wasm-go/extensions/ai-a2as/main.go
  • plugins/wasm-go/extensions/ai-a2as/main_test.go
  • plugins/wasm-go/extensions/ai-a2as/rfc9421.go

💡 小贴士

与 lingma-agents 交流的方式

📜 直接回复评论
直接回复本条评论,lingma-agents 将自动处理您的请求。例如:

  • 在当前代码中添加详细的注释说明。

  • 请详细介绍一下你说的 LRU 改造方案,并使用伪代码加以说明。

📜 在代码行处标记
在文件的特定位置创建评论并 @lingma-agents。例如:

  • @lingma-agents 分析这个方法的性能瓶颈并提供优化建议。

  • @lingma-agents 对这个方法生成优化代码。

📜 在讨论中提问
在任何讨论中 @lingma-agents 来获取帮助。例如:

  • @lingma-agents 请总结上述讨论并提出解决方案。

  • @lingma-agents 请根据讨论内容生成优化代码。

Comment on lines 338 to 340
if policy.Severity == "" {
c.CodifiedPolicies.Policies[i].Severity = "medium"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应统一处理策略规则严重性级别的默认值。

🟡 Major | 🧹 Code Smells

📋 问题详情

Validate()方法中,对于每个PolicyRule,如果没有指定Severity字段,则会被自动设置为"medium"。然而这个逻辑是在验证阶段完成的,而不是在配置解析阶段。这可能导致在实际应用这些策略之前,它们的状态并不一致。理想情况下,所有默认值应在配置加载后立即确定,以便在整个生命周期内保持一致性。

💡 解决方案

建议将默认严重性级别设置移到ParseConfig函数中,确保在配置初始化完成后就具备完整的结构。

+	// Set default severity for policies
+	for i := range config.CodifiedPolicies.Policies {
+		if config.CodifiedPolicies.Policies[i].Severity == "" {
+			config.CodifiedPolicies.Policies[i].Severity = "medium"
+		}
+	}

您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)

有用意见👍无用意见👎错误意见❌

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应统一处理策略规则严重性级别的默认值。

🟡 Major | 🧹 Code Smells

📋 问题详情

Validate()方法中,对于每个PolicyRule,如果没有指定Severity字段,则会被自动设置为"medium"。然而这个逻辑是在验证阶段完成的,而不是在配置解析阶段。这可能导致在实际应用这些策略之前,它们的状态并不一致。理想情况下,所有默认值应在配置加载后立即确定,以便在整个生命周期内保持一致性。

💡 解决方案

建议将默认严重性级别设置移到ParseConfig函数中,确保在配置初始化完成后就具备完整的结构。

+	// Set default severity for policies
+	for i := range config.CodifiedPolicies.Policies {
+		if config.CodifiedPolicies.Policies[i].Severity == "" {
+			config.CodifiedPolicies.Policies[i].Severity = "medium"
+		}
+	}

您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)

有用意见👍无用意见👎错误意见❌

当前是否还有问题

Copy link

@lingma-agents lingma-agents bot Oct 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 Libres-coder,关于 lingma-agents 提出的建议,目前在代码中已经实现了在 ParseConfig 函数中设置默认严重性级别的逻辑(第 281-285 行):

for i := range config.CodifiedPolicies.Policies {
    if config.CodifiedPolicies.Policies[i].Severity == "" {
        config.CodifiedPolicies.Policies[i].Severity = "medium"
    }
}

这段代码确保了在配置解析阶段就为所有策略规则设置了默认的严重性级别,而不是在验证阶段。因此,这个代码异味问题已经得到了解决,配置在整个生命周期内保持了一致性。

不过,我注意到在 Validate() 方法(第 363-370 行)中仍有一段检查 Severity 的代码。虽然这段代码本身没有问题,但它实际上是多余的,因为所有策略规则在 ParseConfig 中已经设置了默认值。可以考虑简化或删除这部分验证逻辑以避免重复检查。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 Libres-coder,关于 lingma-agents 提出的建议,目前在代码中已经实现了在 ParseConfig 函数中设置默认严重性级别的逻辑(第 281-285 行):

for i := range config.CodifiedPolicies.Policies {
    if config.CodifiedPolicies.Policies[i].Severity == "" {
        config.CodifiedPolicies.Policies[i].Severity = "medium"
    }
}

这段代码确保了在配置解析阶段就为所有策略规则设置了默认的严重性级别,而不是在验证阶段。因此,这个代码异味问题已经得到了解决,配置在整个生命周期内保持了一致性。

不过,我注意到在 Validate() 方法(第 363-370 行)中仍有一段检查 Severity 的代码。虽然这段代码本身没有问题,但它实际上是多余的,因为所有策略规则在 ParseConfig 中已经设置了默认值。可以考虑简化或删除这部分验证逻辑以避免重复检查。

请问是否还有问题

Copy link

@lingma-agents lingma-agents bot Oct 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 Libres-coder,根据你的提问,目前关于策略规则严重性级别默认值的处理已经按照建议在 ParseConfig 函数中完成了(第 281-285 行)。这段代码确保了所有策略规则在配置解析阶段就设置了默认的严重性级别,而不是在验证阶段,这样可以保证配置在整个生命周期内的一致性。

虽然在 Validate() 方法(第 363-368 行)中仍然存在对 Severity 字段的检查逻辑,但这部分代码的作用是验证严重性级别是否为合法值,而不是设置默认值,因此是合理的存在。这部分检查确保了即使手动设置了不合法的严重性级别也能被检测到。

综上所述,当前代码已经解决了 lingma-agents 提出的问题,没有其他问题需要处理。

Comment on lines 90 to 93
if err != nil {
log.Errorf("[A2AS] Failed to apply transformations: %v", err)
return types.ActionContinue
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

错误处理方式应更具弹性。

🟡 Major | 🐞 Bugs

📋 问题详情

在多个地方遇到错误时直接返回types.ActionContinue,忽略了错误的影响。比如在onHttpRequestBody中,如果applyA2ASTransformations失败,只是简单跳过了整个处理流程而没有通知客户端发生了什么。这种静默失败不利于排查问题,特别是在复杂部署环境下。

💡 解决方案

对于关键路径上的错误,考虑向客户端发送适当的HTTP响应码和错误详情。

-	if err != nil {
-		log.Errorf("[A2AS] Failed to apply transformations: %v", err)
-		return types.ActionContinue
-	}
+	if err != nil {
+		log.Errorf("[A2AS] Failed to apply transformations: %v", err)
+		_ = proxywasm.SendHttpResponse(500, [][2]string{{"content-type", "application/json"}}, []byte(`{"error":"internal_error","message":"Failed to process request due to internal error."}`), -1)
+		return types.ActionPause
+	}

您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)

有用意见👍无用意见👎错误意见❌

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

错误处理方式应更具弹性。

🟡 Major | 🐞 Bugs

📋 问题详情

在多个地方遇到错误时直接返回types.ActionContinue,忽略了错误的影响。比如在onHttpRequestBody中,如果applyA2ASTransformations失败,只是简单跳过了整个处理流程而没有通知客户端发生了什么。这种静默失败不利于排查问题,特别是在复杂部署环境下。

💡 解决方案

对于关键路径上的错误,考虑向客户端发送适当的HTTP响应码和错误详情。

-	if err != nil {
-		log.Errorf("[A2AS] Failed to apply transformations: %v", err)
-		return types.ActionContinue
-	}
+	if err != nil {
+		log.Errorf("[A2AS] Failed to apply transformations: %v", err)
+		_ = proxywasm.SendHttpResponse(500, [][2]string{{"content-type", "application/json"}}, []byte(`{"error":"internal_error","message":"Failed to process request due to internal error."}`), -1)
+		return types.ActionPause
+	}

您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)

有用意见👍无用意见👎错误意见❌

当前是否还有问题

Copy link

@lingma-agents lingma-agents bot Oct 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Libres-coder 您好,关于这个问题,我们已经做了一部分改进。可以看到,在当前代码中,大多数错误情况都已经采用了更合理的处理方式:

  1. 在第91-97行,当 applyA2ASTransformations 失败时,会发送一个 HTTP 500 响应并暂停请求处理。 2. 在第75-82行,签名验证失败时也会发送 HTTP 403 响应并暂停处理。 3. 在第100-108行,工具调用被拒绝时同样会返回 HTTP 403 错误。
    不过确实还有一处可以优化的地方:在第110-113行,当替换请求体失败时(proxywasm.ReplaceHttpRequestBody 出错),目前只是记录了日志然后继续执行,这可能会导致后续处理出现问题。根据 @lingma-agents 的建议,我们也应该在这里发送错误响应而不是静默失败。
    总的来说,大部分关键路径上的错误都已正确处理,但仍有小部分边缘情况需要完善。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Libres-coder 您好,关于这个问题,我们已经做了一部分改进。可以看到,在当前代码中,大多数错误情况都已经采用了更合理的处理方式:

  1. 在第91-97行,当 applyA2ASTransformations 失败时,会发送一个 HTTP 500 响应并暂停请求处理。 2. 在第75-82行,签名验证失败时也会发送 HTTP 403 响应并暂停处理。 3. 在第100-108行,工具调用被拒绝时同样会返回 HTTP 403 错误。
    不过确实还有一处可以优化的地方:在第110-113行,当替换请求体失败时(proxywasm.ReplaceHttpRequestBody 出错),目前只是记录了日志然后继续执行,这可能会导致后续处理出现问题。根据 @lingma-agents 的建议,我们也应该在这里发送错误响应而不是静默失败。
    总的来说,大部分关键路径上的错误都已正确处理,但仍有小部分边缘情况需要完善。

当前是否还有问题

Copy link

@lingma-agents lingma-agents bot Oct 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Libres-coder 根据代码审查和之前的讨论,目前主要的错误处理已经得到了改进,大部分关键路径上的错误都有了适当的响应机制。不过,仍有一个地方可以进一步优化:

在第110-116行,当proxywasm.ReplaceHttpRequestBody调用失败时,虽然会发送500错误响应,但仍然返回types.ActionPause,这是正确的处理方式。这部分已经按照建议进行了修复。

整体来看,错误处理机制已经相对完善,主要的错误情况都有明确的反馈,不再是静默失败。除非有其他特定场景需要处理,当前的实现应该是满足要求的。

Comment on lines 372 to 375
body, err := proxywasm.GetHttpRequestBody(0, 10*1024*1024)
if err != nil {
return fmt.Errorf("failed to get request body for signature verification: %v", err)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

请求体大小限制应当更加灵活和可控。

🟢 Minor | 🧹 Code Smells

📋 问题详情

verifySimpleSignature函数中,获取HTTP请求体时硬编码了一个最大长度(10MB)。这种方式缺乏灵活性,不同环境或需求下的最优值可能差异很大。建议将其提取为配置参数,让用户可以根据实际情况调整阈值。

💡 解决方案

将最大请求体大小作为一个新的配置选项加入到AuthenticatedPromptsConfig结构体中,并在此处引用它。

+	// @Title zh-CN 最大请求体大小
+	// @Description zh-CN 用于签名验证的最大请求体大小(字节),默认10MB
+	MaxRequestBodySize int `json:"maxRequestBodySize"`

然后更新相关初始化代码:

+	if config.AuthenticatedPrompts.MaxRequestBodySize == 0 {
+		config.AuthenticatedPrompts.MaxRequestBodySize = 10 * 1024 * 1024
+	}

最终替换原代码中的硬编码部分:

-	body, err := proxywasm.GetHttpRequestBody(0, 10*1024*1024)
+	body, err := proxywasm.GetHttpRequestBody(0, config.AuthenticatedPrompts.MaxRequestBodySize)

您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)

有用意见👍无用意见👎错误意见❌

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

请求体大小限制应当更加灵活和可控。

🟢 Minor | 🧹 Code Smells

📋 问题详情

verifySimpleSignature函数中,获取HTTP请求体时硬编码了一个最大长度(10MB)。这种方式缺乏灵活性,不同环境或需求下的最优值可能差异很大。建议将其提取为配置参数,让用户可以根据实际情况调整阈值。

💡 解决方案

将最大请求体大小作为一个新的配置选项加入到AuthenticatedPromptsConfig结构体中,并在此处引用它。

+	// @Title zh-CN 最大请求体大小
+	// @Description zh-CN 用于签名验证的最大请求体大小(字节),默认10MB
+	MaxRequestBodySize int `json:"maxRequestBodySize"`

然后更新相关初始化代码:

+	if config.AuthenticatedPrompts.MaxRequestBodySize == 0 {
+		config.AuthenticatedPrompts.MaxRequestBodySize = 10 * 1024 * 1024
+	}

最终替换原代码中的硬编码部分:

-	body, err := proxywasm.GetHttpRequestBody(0, 10*1024*1024)
+	body, err := proxywasm.GetHttpRequestBody(0, config.AuthenticatedPrompts.MaxRequestBodySize)

您的反馈对我们很重要!(建议右键在新标签页中打开以下链接)

有用意见👍无用意见👎错误意见❌

其余问题已处理,请求体大小限制由于10MB预估应该能处理大部分情况,调整收益较小,因此暂时没有对这一问题进行相应的调整

Copy link

@lingma-agents lingma-agents bot Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 Libres-coder,

关于这个代码评审意见,@lingma-agents 提出了一个很好的建议。虽然你说10MB已经能满足大多数场景,但把这个值做成可配置项确实会增加插件的灵活性。

当前代码中这行是硬编码的:

body, err := proxywasm.GetHttpRequestBody(0, 10*1024*1024)

如果将来有更大的请求体需要处理,或者希望在资源受限环境中使用更小的限制,现在的硬编码方式就需要重新编译插件才能修改。

按照建议添加配置项可以让用户根据自己的实际需求来设置合适的值,提升插件的通用性和适应性。当然,如果你们评估后认为目前没有必要支持这个配置项,也可以维持现状,但在代码注释里说明这个设计决策会更好。

你对是否要实现这个建议有什么看法?如果有需要,我可以帮你一起讨论具体的实现细节。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 Libres-coder,

关于这个代码评审意见,@lingma-agents 提出了一个很好的建议。虽然你说10MB已经能满足大多数场景,但把这个值做成可配置项确实会增加插件的灵活性。

当前代码中这行是硬编码的:

body, err := proxywasm.GetHttpRequestBody(0, 10*1024*1024)

如果将来有更大的请求体需要处理,或者希望在资源受限环境中使用更小的限制,现在的硬编码方式就需要重新编译插件才能修改。

按照建议添加配置项可以让用户根据自己的实际需求来设置合适的值,提升插件的通用性和适应性。当然,如果你们评估后认为目前没有必要支持这个配置项,也可以维持现状,但在代码注释里说明这个设计决策会更好。

你对是否要实现这个建议有什么看法?如果有需要,我可以帮你一起讨论具体的实现细节。

已调整相应的请求体大小限制,请问是否有问题,是否还有需要调整的地方

Copy link

@lingma-agents lingma-agents bot Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 Libres-coder,

看起来你已经根据建议调整了请求体大小限制的处理方式。从代码来看,你现在将 maxBodySize 作为参数传递给 verifySignatureverifySimpleSignature 函数,而不是硬编码 10*1024*1024

这是一个很好的改进,因为它使代码更具灵活性和可配置性。不过我注意到你还没有实现建议中的配置项部分,即在 AuthenticatedPromptsConfig 结构体中添加 MaxRequestBodySize 字段并在配置初始化时设置默认值。

目前你的实现是将 maxBodySize 作为参数传递,这解决了硬编码的问题,但如果能进一步将其作为可配置项,用户就可以根据自己的需求调整这个值,而不需要修改代码。

总体来说,你的修改是朝着正确方向迈出的一步。如果将来需要进一步完善,可以考虑添加配置项来使这个值完全可配置。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 Libres-coder,

看起来你已经根据建议调整了请求体大小限制的处理方式。从代码来看,你现在将 maxBodySize 作为参数传递给 verifySignatureverifySimpleSignature 函数,而不是硬编码 10*1024*1024

这是一个很好的改进,因为它使代码更具灵活性和可配置性。不过我注意到你还没有实现建议中的配置项部分,即在 AuthenticatedPromptsConfig 结构体中添加 MaxRequestBodySize 字段并在配置初始化时设置默认值。

目前你的实现是将 maxBodySize 作为参数传递,这解决了硬编码的问题,但如果能进一步将其作为可配置项,用户就可以根据自己的需求调整这个值,而不需要修改代码。

总体来说,你的修改是朝着正确方向迈出的一步。如果将来需要进一步完善,可以考虑添加配置项来使这个值完全可配置。

已做出相应调整,请问是否还有需要调整的内容

Copy link

@lingma-agents lingma-agents bot Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 Libres-coder,

我看到你已经对代码进行了调整,将原本硬编码的请求体大小限制改为了通过参数传递的方式,这是个不错的改进。现在 verifySimpleSignature 函数接收一个 maxBodySize 参数而不是直接使用固定的 10MB 限制。

不过我还注意到一些可以进一步优化的地方:

  1. 根据代码逻辑,我看到你在 onHttpRequestBody 函数中设置了默认的 maxRequestBodySize 值:
    maxRequestBodySize := config.MaxRequestBodySize
    if config.AuthenticatedPrompts.MaxRequestBodySize > 0 {
        maxRequestBodySize = config.AuthenticatedPrompts.MaxRequestBodySize
    }

但是我没有看到 AuthenticatedPromptsConfig 结构体中定义 MaxRequestBodySize 字段,也没有看到在配置解析时设置默认值的相关代码。

  1. 如果要完整实现这个功能,建议:
    • AuthenticatedPromptsConfig 结构体中添加 MaxRequestBodySize 字段
    • 在配置解析阶段设置默认值(如 10MB)
    • 使用配置文件中的值覆盖默认值

这样用户就可以通过配置文件来自定义请求体大小限制,而无需修改代码。

总体来说你的改动是积极的,只是建议进一步完善配置化支持以提高插件的易用性。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 Libres-coder,

我看到你已经对代码进行了调整,将原本硬编码的请求体大小限制改为了通过参数传递的方式,这是个不错的改进。现在 verifySimpleSignature 函数接收一个 maxBodySize 参数而不是直接使用固定的 10MB 限制。

不过我还注意到一些可以进一步优化的地方:

  1. 根据代码逻辑,我看到你在 onHttpRequestBody 函数中设置了默认的 maxRequestBodySize 值:
    maxRequestBodySize := config.MaxRequestBodySize
    if config.AuthenticatedPrompts.MaxRequestBodySize > 0 {
        maxRequestBodySize = config.AuthenticatedPrompts.MaxRequestBodySize
    }

但是我没有看到 AuthenticatedPromptsConfig 结构体中定义 MaxRequestBodySize 字段,也没有看到在配置解析时设置默认值的相关代码。

  1. 如果要完整实现这个功能,建议:

    • AuthenticatedPromptsConfig 结构体中添加 MaxRequestBodySize 字段
    • 在配置解析阶段设置默认值(如 10MB)
    • 使用配置文件中的值覆盖默认值

这样用户就可以通过配置文件来自定义请求体大小限制,而无需修改代码。

总体来说你的改动是积极的,只是建议进一步完善配置化支持以提高插件的易用性。

似乎我已经实现了,能否请你再检验一次呢

Copy link

@lingma-agents lingma-agents bot Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

你好 Libres-coder,

我看了一下你的最新代码,确认你已经实现了之前建议的功能。让我详细解释一下当前的实现:

  1. 你在 AuthenticatedPromptsConfig 中添加了 MaxRequestBodySize 字段(第72行):

    if config.AuthenticatedPrompts.MaxRequestBodySize > 0 {
        maxRequestBodySize = config.AuthenticatedPrompts.MaxRequestBodySize
    }
  2. 你还在全局配置中添加了 MaxRequestBodySize 字段(第71行),提供了默认值:

    maxRequestBodySize := config.MaxRequestBodySize
  3. 最重要的是,你现在调用 verifySignature 时传入了这个动态计算的 maxRequestBodySize 值,而不是硬编码的 10*1024*1024

这样的实现允许用户通过配置来控制请求体的最大大小,既保留了默认值,又提供了自定义能力,完全满足了之前提出的需求。代码结构清晰,易于理解和维护。

我认为当前实现已经很好了,没有发现需要进一步调整的地方。

@Libres-coder
Copy link
Contributor Author

Libres-coder commented Oct 23, 2025

@Libres-coder
Copy link
Contributor Author

🔎 代码评审报告

🎯 评审意见概览
严重度 数量 说明
🔴 Blocker 0 阻断性问题,需立即修复。例如:系统崩溃、关键功能不可用或严重安全漏洞。
🟠 Critical 1 严重问题,高优先级修复。例如:核心功能异常或性能瓶颈影响用户体验。
🟡 Major 2 主要问题,建议修复。例如:非核心功能缺陷或代码维护性较差。
🟢 Minor 1 次要问题,酬情优化。例如:代码格式不规范或注释缺失。
总计: 4 个问题

📋 评审意见详情
💡 代码实现建议

以下是文件级别的代码建议,聚焦于代码的可读性、可维护性和潜在问题。

🔹 plugins/wasm-go/extensions/ai-a2as/config.go (1 💬)

🔹 plugins/wasm-go/extensions/ai-a2as/main.go (3 💬)

🚀 架构设计建议

以下是对代码架构和设计的综合分析,聚焦于跨文件交互、系统一致性和潜在优化空间。

🔍1. 架构一致性问题:插件执行阶段与预期不符
根据 README 文档描述,插件应在 AUTHN 阶段执行,优先级为 200。然而,config.go 文件中的注释表明插件可能在其他阶段运行。这种不一致可能导致插件无法按预期顺序执行,影响安全策略的有效性。需要确认插件实际执行阶段,并更新文档或代码以保持一致。

📌 关键代码

插件执行阶段:`AUTHN`(认证阶段,在 ai-proxy 之前执行)  
插件执行优先级:`200`
// @Name ai-a2as
// @Category ai
// @Phase AUTHN
// @Priority 200
// @Title zh-CN AI Agent-to-Agent 安全
// @Title en-US AI Agent-to-Agent Security
// @Description zh-CN 实现 OWASP A2AS 框架,为 AI 应用提供深度防御,防范提示注入攻击
// @Description en-US Implements OWASP A2AS framework to provide defense in depth for AI applications against prompt injection attacks

⚠️ 潜在风险

插件执行顺序错误可能导致安全策略失效,使系统易受提示注入攻击。

🔍2. 跨文件问题:消费者特定配置合并逻辑不完整
虽然 config.go 中实现了 MergeConsumerConfig 方法来合并消费者特定配置,但该方法仅替换了整个配置对象,而非逐字段合并。这可能导致部分配置丢失或覆盖不当。此外,README 中提到的配置合并规则并未在代码中完全体现。建议完善合并逻辑,确保消费者特定配置能够正确地覆盖全局配置。

📌 关键代码

func (c *A2ASConfig) MergeConsumerConfig(consumerName string) A2ASConfig {
	if consumerName == "" || len(c.ConsumerConfigs) == 0 {
		return *c
	}

	consumerConfig, exists := c.ConsumerConfigs[consumerName]
	if !exists {
		return *c
	}

	merged := *c

	if consumerConfig.SecurityBoundaries != nil {
		merged.SecurityBoundaries = *consumerConfig.SecurityBoundaries
	}

	if consumerConfig.InContextDefenses != nil {
		merged.InContextDefenses = *consumerConfig.InContextDefenses
	}

	if consumerConfig.BehaviorCertificates != nil {
		merged.BehaviorCertificates = *consumerConfig.BehaviorCertificates
	}

	if consumerConfig.CodifiedPolicies != nil {
		merged.CodifiedPolicies = *consumerConfig.CodifiedPolicies
	}

	return merged
}
**配置合并规则**:
1. 如果请求包含 `X-Mse-Consumer` 头,插件会查找对应的消费者配置
2. 消费者特定配置会覆盖全局配置(仅覆盖已设置的字段)
3. 如果消费者没有特定配置,使用全局配置

⚠️ 潜在风险

配置合并错误可能导致某些安全策略未正确应用,降低系统的安全性。

🔍3. 技术债务:签名验证功能未完全实现 RFC 9421 标准
尽管 README 和代码中提到了 RFC 9421 签名验证,但当前实现仅为简化版 HMAC-SHA256 验证。完整的 RFC 9421 实现在未来版本中计划提供。目前的实现缺乏对签名参数解析、时间戳和 nonce 验证等功能的支持,存在潜在的安全隐患。建议尽快完成 RFC 9421 的完整实现,以提高签名验证的安全性和可靠性。

📌 关键代码

> **版本说明**: v1.0.0 实现了基于 HMAC-SHA256 的简化签名验证。完整的 RFC 9421 实现将在未来版本中提供。
type AuthenticatedPromptsConfig struct {
	// @Title zh-CN 启用签名验证
	// @Description zh-CN 是否启用 RFC 9421 HTTP 消息签名验证
	Enabled bool `json:"enabled"`

	// @Title zh-CN 签名模式
	// @Description zh-CN 签名验证模式:simple(简化HMAC,默认)或 rfc9421(完整RFC 9421标准)
	Mode string `json:"mode"`

	// @Title zh-CN 签名头名称
	// @Description zh-CN HTTP 签名头的名称
	SignatureHeader string `json:"signatureHeader"`

	// @Title zh-CN 共享密钥
	// @Description zh-CN 用于 HMAC 签名验证的共享密钥(base64编码)
	SharedSecret string `json:"sharedSecret"`

	// @Title zh-CN 签名算法
	// @Description zh-CN 签名算法:hmac-sha256(默认)
	Algorithm string `json:"algorithm"`

	// @Title zh-CN 允许的时钟偏差
	// @Description zh-CN 允许的时钟偏差(秒),默认300秒
	ClockSkew int `json:"clockSkew"`

	// @Title zh-CN 允许无签名请求
	// @Description zh-CN 当设置为 true 时,允许没有签名的请求通过;为 false 时,缺少签名的请求将被拒绝
	AllowUnsigned bool `json:"allowUnsigned"`

	// @Title zh-CN RFC 9421 特定配置
	// @Description zh-CN RFC 9421 完整模式的特定配置项
	RFC9421 RFC9421Config `json:"rfc9421,omitempty"`
}

⚠️ 潜在风险

签名验证机制不够健壮,容易受到中间人攻击或重放攻击,影响系统的整体安全性。

🔍4. 可维护性问题:文档和代码中的配置字段描述不一致
README 和 config.go 中对于某些配置字段的描述存在差异。例如,AuthenticatedPromptsConfig 中的 SharedSecret 字段在 README 中标记为条件必填,而在 config.go 的注释中则没有明确指出这一点。这种不一致增加了理解和维护配置的难度,可能导致配置错误。建议统一文档和代码中的字段描述,确保一致性。

📌 关键代码

| `authenticatedPrompts.sharedSecret` | string | 条件必填* | - | HMAC 共享密钥(支持 base64 或原始字符串) |
// @Title zh-CN 共享密钥
	// @Description zh-CN 用于 HMAC 签名验证的共享密钥(base64编码)
	SharedSecret string `json:"sharedSecret"`

⚠️ 潜在风险

配置理解困难,导致错误配置,进而影响插件的功能和安全性。

审查详情
📒 文件清单 (9 个文件)

新增: 9 个文件

✅ 新增文件:

  • plugins/wasm-go/extensions/ai-a2as/Makefile
  • plugins/wasm-go/extensions/ai-a2as/README.md
  • plugins/wasm-go/extensions/ai-a2as/README_EN.md
  • plugins/wasm-go/extensions/ai-a2as/config.go
  • plugins/wasm-go/extensions/ai-a2as/go.mod
  • plugins/wasm-go/extensions/ai-a2as/go.sum
  • plugins/wasm-go/extensions/ai-a2as/main.go
  • plugins/wasm-go/extensions/ai-a2as/main_test.go
  • plugins/wasm-go/extensions/ai-a2as/rfc9421.go

💡 小贴士

感谢反馈,当前你给出的反馈和评论我都根据其做出了调整,除了请求体大小限制由于10MB预估应该能处理大部分情况,调整收益较小因此没有处理外,其余问题都已对其进行了调整。能否请你重新检验一下,是否还有问题

@codecov-commenter
Copy link

codecov-commenter commented Oct 24, 2025

Codecov Report

❌ Patch coverage is 87.61805% with 118 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.99%. Comparing base (ef31e09) to head (310d40c).
⚠️ Report is 772 commits behind head on main.

Files with missing lines Patch % Lines
plugins/wasm-go/extensions/ai-a2as/main.go 72.05% 38 Missing and 19 partials ⚠️
plugins/wasm-go/extensions/ai-a2as/config.go 66.46% 41 Missing and 15 partials ⚠️
...o/extensions/ai-a2as/test/defenses_and_policies.go 97.75% 4 Missing ⚠️
...o/extensions/ai-a2as/test/authenticated_prompts.go 99.51% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main    #3045       +/-   ##
===========================================
+ Coverage   35.91%   46.99%   +11.08%     
===========================================
  Files          69       88       +19     
  Lines       11576    11870      +294     
===========================================
+ Hits         4157     5578     +1421     
+ Misses       7104     5929     -1175     
- Partials      315      363       +48     
Flag Coverage Δ
wasm-go-plugin-ai-a2as 87.61% <87.61%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...o/extensions/ai-a2as/test/behavior_certificates.go 100.00% <100.00%> (ø)
...ns/wasm-go/extensions/ai-a2as/test/per_consumer.go 100.00% <100.00%> (ø)
...o/extensions/ai-a2as/test/authenticated_prompts.go 99.51% <99.51%> (ø)
...o/extensions/ai-a2as/test/defenses_and_policies.go 97.75% <97.75%> (ø)
plugins/wasm-go/extensions/ai-a2as/config.go 66.46% <66.46%> (ø)
plugins/wasm-go/extensions/ai-a2as/main.go 72.05% <72.05%> (ø)

... and 97 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@johnlanni
Copy link
Collaborator

@Libres-coder Could you please add me on DingTalk: chengtanzty
I will add you to the Agent SIG. This feature can be further discussed with other developers in the Agent SIG.

@johnlanni
Copy link
Collaborator

image The unit test coverage needs to be improved

@Libres-coder
Copy link
Contributor Author

@Libres-coder Could you please add me on DingTalk: chengtanzty I will add you to the Agent SIG. This feature can be further discussed with other developers in the Agent SIG.

Thank you for your reply! I have adjusted the corresponding test content and feature-related materials, and sent you a friend request on DingTalk. Hope you can accept it to proceed with further communication @johnlanni

Libres-coder and others added 12 commits October 25, 2025 21:09
…cture

- Remove UTF-8 BOM from 4 test files (fixes CI build error)
- Add .gitignore to exclude build artifacts
- Add README_dev.md for development guidelines
- Add option.yaml for hgctl configuration

Fixes compilation error: 'invalid BOM in the middle of the file'
Remove redundant empty check in Validate() since ParseConfig already
ensures all policies have a default severity value of medium.

This addresses lingma-agents' suggestion to simplify the validation
logic after default values are set during configuration parsing.
When ReplaceHttpRequestBody fails, the security transformations are not
applied but the request would continue. This could be a security risk.

Now properly return HTTP 500 and ActionPause to prevent the request from
proceeding with unprotected content.

Addresses lingma-agents' suggestion for edge case handling.
- 新增 escapeA2ASTags 函数,转义用户输入中的A2AS标签
- 在 WrapWithSecurityTag 中自动调用转义,防止标签伪造
- 添加11个测试用例,覆盖各种标签注入场景
- 更新README,添加安全特性说明
- 提升测试覆盖率和代码安全性

Closes: #防止标签伪造攻击
Related: OWASP A2AS论文 - 安全边界最佳实践
@Libres-coder
Copy link
Contributor Author

Libres-coder commented Oct 28, 2025

Hi maintainers,

The ai-a2as plugin builds successfully, but the CI fails at the e2e test stage with go: updates to go.mod needed. This appears to be an issue with the test framework itself, not the plugin code.I've noticed this issue is also affecting other PRs, so it appears to be a temporary infrastructure issue rather than a problem with my code.I've checked the relevant content, and it appears that the tools/hack/prebuild.shscript updated the go.modfiles in the submodules but failed to update the root go.mod, resulting in a go: updates to go.mod needederror during the end-to-end (e2e) tests. I've submitted PR #3069 to add the missing go mod tidy step. Once that infrastructure fix is merged, this PR should pass CI successfully. @johnlanni @CH3CHO @rinfx @wydream @erasernoob
image

@johnlanni
Copy link
Collaborator

@Libres-coder Yeah, I fixed it

- Nonce Verification (防重放攻击,21个测试)
  * Configurable nonce header, expiry, and min length
  * Automatic replay attack detection and blocking
  * 7 unit tests + 14 integration tests

- Key Rotation (零停机密钥轮换,10个测试)
  * Multi-key coexistence verification support
  * Key status management (active/deprecated/revoked)
  * Progressive key rotation workflow

- Audit Logging (完整安全审计,9个测试)
  * Configurable log level and event filtering
  * Production and development preset configurations
  * Comprehensive security event auditing

- Enhanced Metrics (8个新监控指标)
  * Nonce verification metrics (4)
  * Key rotation metrics (2)
  * Audit log metrics (2)

- Complete Documentation (中英文文档同步)
  * Updated README.md and README_EN.md (+740 lines)
  * Comprehensive usage examples and troubleshooting
  * Updated README_dev.md with test instructions

Quality Metrics:
- Test Coverage: 73.8%
- Test Pass Rate: 100% (261/261 assertions)
- WASM Build: Success (2017.29 KB)
- Code Quality: go fmt + go vet passed

Total Changes: 2,218 lines of code
- Core implementation: +753 lines
- Test code: +715 lines
- Documentation: +750 lines
@Libres-coder
Copy link
Contributor Author

Hi @johnlanni ,

I've updated the ai-a2as plugin with comprehensive security enhancements building upon the complete OWASP A2AS BASIC framework. The release introduces Nonce verification for replay attack prevention with configurable expiry and validation (21 tests), zero-downtime Key Rotation supporting multi-key coexistence and seamless secret updates (10 tests), and Audit Logging with flexible event filtering and compliance support (9 tests). Additionally, 14 Prometheus metrics provide complete observability across security operations. All tests pass with bilingual documentation.

Current limitations: (1) resource limits only enforce request body size, not memory/execution time/API rates, (2) trust level hierarchy lacks numerical mapping for dynamic threat response, (3) policy hash binding for tamper detection is not implemented, (4) multi-agent communication security requires framework-level integration beyond single plugin scope, (5) multimodal input (image/audio) is not supported. These represent future enhancement opportunities and do not affect core text-based LLM security functionality.

Notable innovations beyond paper specification: tag injection prevention via HTML entity encoding to prevent forged security boundaries, automatic Content-Digest computation for RFC 9421 simplifying client integration, and granular per-consumer nonce configuration.

| `maxRequestBodySize` | int | 非必填 | 10485760 | 最大请求体大小(字节),范围:1KB (1024) - 100MB (104857600) |

### Security Boundaries (S) - 安全边界

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Boundaries 我的理解应该是在Agent侧实现?在网关侧实现意义感觉不是很大,除非网关侧要做一些上下文编辑

|------|---------|------|
| `name` | string | 策略名称 |
| `content` | string | 策略内容(自然语言) |
| `severity` | string | 严重程度:critical, high, medium, low |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A2AS标准目前似乎没有对policies做严重程度的要求,这里是否过度设计了

Comment on lines 145 to 162
**🔐 Nonce 验证配置(防重放攻击)** (v1.2.0+):

| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|------|---------|---------|--------|------|
| `authenticatedPrompts.enableNonceVerification` | bool | 非必填 | false | 是否启用 Nonce 验证 |
| `authenticatedPrompts.nonceHeader` | string | 非必填 | "X-A2AS-Nonce" | Nonce 请求头名称 |
| `authenticatedPrompts.nonceExpiry` | int | 非必填 | 300 | Nonce 过期时间(秒) |
| `authenticatedPrompts.nonceMinLength` | int | 非必填 | 16 | Nonce 最小长度(字符) |

**🔄 密钥轮换配置** (v1.2.0+):

| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|------|---------|---------|--------|------|
| `authenticatedPrompts.secretKeys` | array | 非必填 | [] | 密钥列表(支持多密钥验证和轮换) |
| `authenticatedPrompts.secretKeys[].keyId` | string | 必填 | - | 密钥唯一标识 |
| `authenticatedPrompts.secretKeys[].secret` | string | 必填 | - | 密钥值(base64 或原始字符串) |
| `authenticatedPrompts.secretKeys[].isPrimary` | bool | 非必填 | false | 是否为主密钥(用于签名) |
| `authenticatedPrompts.secretKeys[].status` | string | 非必填 | "active" | 密钥状态:active, deprecated, revoked |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如上所述,第一版功能尽量简单实现,现阶段可以不需要考虑重放和密钥轮转

| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
|------|---------|---------|--------|------|
| `authenticatedPrompts.enabled` | bool | 非必填 | false | 是否启用签名验证 |
| `authenticatedPrompts.mode` | string | 非必填 | "simple" | 签名验证模式:`simple` 或 `rfc9421` |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

规范有指定使用rfc9421吗,如果没有的话,先只支持simple模式即可

Comment on lines 135 to 142
| `authenticatedPrompts.algorithm` | string | 非必填 | "hmac-sha256" | 签名算法(当前仅支持 hmac-sha256) |
| `authenticatedPrompts.clockSkew` | int | 非必填 | 300 | 允许的时钟偏差(秒) |
| `authenticatedPrompts.allowUnsigned` | bool | 非必填 | false | 是否允许无签名的请求通过 |
| `authenticatedPrompts.rfc9421` | object | 非必填 | - | RFC 9421 特定配置(仅当 mode=rfc9421 时使用) |
| `authenticatedPrompts.rfc9421.requiredComponents` | array | 非必填 | `["@method", "@path", "content-digest"]` | 必需的签名组件 |
| `authenticatedPrompts.rfc9421.maxAge` | int | 非必填 | 300 | 签名最大有效期(秒) |
| `authenticatedPrompts.rfc9421.enforceExpires` | bool | 非必填 | true | 是否强制验证 expires 参数 |
| `authenticatedPrompts.rfc9421.requireContentDigest` | bool | 非必填 | true | 是否要求 Content-Digest 头 |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果目前规范对这些签名算法细节未作要求,应该先简单实现,不要做过度设计

@@ -0,0 +1,82 @@
## 构建方法

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个文档不需要提交

config.setGaugeMetric(metricA2ASActiveKeysCount, uint64(activeKeysCount))
}

if err := verifySignature(config.AuthenticatedPrompts, maxRequestBodySize); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我建议验签完成后应该移除签名,因为llm并不认识签名,带上一串签名可能导致预期外的行为

# 发送请求
curl -X POST https://your-gateway/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Signature: $SIGNATURE" \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A2AS有规范需要带Signature头吗?我的理解是只对body里user和input中设置签名,在网关进行验签


action := host.CallOnHttpRequestBody([]byte(requestBody))

// email.read_message �?allowedTools 中,应该允许
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

乱码注释?注释尽量用英文吧

- 在 Security Boundaries 章节添加区别说明框
- 明确 includeContentDigest 不是签名机制,仅用于审计追踪
- 更新中英文 README,避免混淆两个独立的安全机制
- 响应维护者 @johnlanni 的 review 反馈
@Libres-coder
Copy link
Contributor Author

Libres-coder commented Nov 1, 2025

@johnlanni 感谢您的详细 review!当前实现参考了 OWASP A2AS 论文(https://arxiv.org/abs/2510.13825)。这篇论文在今年 10 月刚发表,提出了针对 AI Agent 的安全框架,类似于 HTTPS 对于 HTTP 的定位。论文里定义了 BASIC 安全模型(Behavior Certificates、Authenticated Prompts、Security Boundaries、In-Context Defenses、Codified Policies),所以我尝试参考实现了一下。不过现在看来,确实有些地方我理解得不太准确,实现得也过于复杂了。

关于您提到的几个点,我想先确认一下:

Security Boundaries:您说应该在 Agent 侧实现,这一点我确实没有考虑。在论文里也只是描述了用 XML 标签包裹内容的机制没有规定一定要在哪一侧实现。我当时考虑的是在网关统一处理,现在看可能不太合适。想确认一下您觉得对于 Higress 来说,这部分功能应该怎么定位?是完全交给 Agent 侧,还是网关只做一些基础的处理?

签名验证:关于签名验证确实是我过度设计了,A2AS 论文里的 Authenticated Prompts 确实是在内容中直接嵌入哈希(像 <a2as:user:7c3d0c6d>content</a2as:user:7c3d0c6d> 这样),没有用到 HTTP Signature 头。我原先想着 RFC 9421 可能会更标准化一些,重新检阅后现在看来也同样偏离了论文的简洁设计。想问下您觉得还有必要网关做签名验证吗?如果需要的话,简单的 HMAC 够用吗?

Nonce 、密钥轮换、详细审计日志这些我确实有点实现的过于复杂了。想确认一下这些功能是完全移除还是保留但提供简化的默认模式,以作为增强功能呢?

而至于其余几项问题:验签后移除签名头、注释和 README_dev.md 我后续均会做出相应的调整。最后想再次确认:对于 Higress 这样的 AI Gateway,您觉得 A2AS 应该做到什么程度?是只做轻量级的安全增强(基础的标签和行为控制),还是保留增强的功能但保持简洁?如若您觉得后续可以将这些功能作为增强功能的话我可以保留并保证基础默认功能的实现。

期待您的指导!


@johnlanni Thanks for the detailed review! The current implementation refers to the OWASP A2AS paper (https://arxiv.org/abs/2510.13825). This paper was just published in October this year and proposes a security framework for AI Agents, similar to the positioning of HTTPS for HTTP. The BASIC security model (Behavior Certificates, Authenticated Prompts, Security Boundaries, In-Context Defenses, Codified Policies) is defined in the paper, so I tried to implement it as a reference. But now it seems that there are indeed some parts that I did not understand accurately and the implementation was too complicated.

Regarding the points you mentioned, I would like to confirm first:

Security Boundaries: You said it should be implemented on the Agent side, which I really didn't consider. The paper only describes the mechanism of wrapping content with XML tags and does not specify which side it must be implemented on. What I considered at the time was unified processing at the gateway, but it may not be appropriate now. Want to confirm how you think this part of the function should be positioned for Higress? Is it completely left to the Agent side, or does the gateway only do some basic processing?

Signature verification: Regarding signature verification, I have indeed over-designed it. The Authenticated Prompts in the A2AS paper does embed the hash directly in the content (like <a2as:user:7c3d0c6d>content</a2as:user:7c3d0c6d>), without using the HTTP Signature header. I originally thought that RFC 9421 might be more standardized, but after re-reviewing it, it seems that it also deviates from the simple design of the paper. I would like to ask, do you think it is still necessary for the gateway to do signature verification? If so, would a simple HMAC suffice?

Nonce, key rotation, detailed audit log These are indeed a bit too complicated for me to implement. Want to confirm whether these features are completely removed or retained but provide a simplified default mode as an enhancement?

As for the remaining issues: remove signature headers, comments and README_dev.md after signature verification, I will make corresponding adjustments in the future. Finally, I want to confirm again: How far do you think A2AS should go for an AI Gateway like Higress? Should we only make lightweight security enhancements (basic tags and behavior controls), or should we retain the enhanced functionality but keep it simple? If you think these functions can be used as enhanced functions in the future, I can retain and ensure the implementation of the basic default functions.

Looking forward to your guidance!

@johnlanni
Copy link
Collaborator

johnlanni commented Nov 1, 2025

@Libres-coder Security Boundaries机制我认为应该是Agent侧加的,网关不需要做处理。
网关需要做签名验证,但只需针对嵌入Hash做验签,并在验签完毕后移除嵌入的Hash。
Nonce 、密钥轮换、详细审计日志等过度设计的实现我建议移除。


@Libres-coder The Security Boundaries mechanism I think should be added on the Agent side, and the gateway does not need to handle it.
The gateway needs to perform signature verification, but it only needs to verify the signature for the embedded Hash, and remove the embedded Hash after the signature verification is completed.
Over-engineered implementations such as Nonce, key rotation, detailed audit logs, etc. I recommend removal.

@Libres-coder
Copy link
Contributor Author

@Libres-coder Security Boundaries机制我认为应该是Agent侧加的,网关不需要做处理。 网关需要做签名验证,但只需针对嵌入Hash做验签,并在验签完毕后移除嵌入的Hash。 Nonce 、密钥轮换、详细审计日志等过度设计的实现我建议移除。

@Libres-coder The Security Boundaries mechanism I think should be added on the Agent side, and the gateway does not need to handle it. The gateway needs to perform signature verification, but it only needs to verify the signature for the embedded Hash, and remove the embedded Hash after the signature verification is completed. Over-engineered implementations such as Nonce, key rotation, detailed audit logs, etc. I recommend removal.

@johnlanni 感谢反馈!后续我会及时根据您的建议重新调整。然后关于签名验证我有两点想再确定一下以避免理解偏差,首先是签名是否由客户端通过 HTTP 头提交?Client是通过HTTP头(如X-A2AS-Signature)提供签名,还是也嵌入在request body中呢?然后相应的流程是否大概如下所示呢
image

@johnlanni
Copy link
Collaborator

johnlanni commented Nov 1, 2025

@Libres-coder A2AS协议有说明要带X-A2AS-Signature头吗?


@Libres-coder Does the A2AS protocol require the X-A2AS-Signature header?

@Libres-coder
Copy link
Contributor Author

Libres-coder commented Nov 2, 2025

@johnlanni 我将此前的复杂设计备份了后,现在已经调整了相应的内容实现了简单地基础内容。签名验证似乎没有强制规定客户端通过 HTTP 头提交,主要是当时我在想是否可以统一在网关层处理,这样能够支持更多种算法实现,也能够将认证、授权、签名验证等操作直接在网关层处理,如若不通过直接在网关就拒绝。后续我重新查看了下相关内容,似乎是在应用层生成和验证,这样的话LLM可以看到Prompt的哈希。HTTP 头提交签名验证似乎职能上不太符合相应的标准,网关层似乎只负责注入统一策略。我现在重新调整了相应的内容,备份原先的复杂设计,只初步提交了第一版本所需的简单实现


@johnlanni After I backed up the previous complex design, I have now adjusted the corresponding content to achieve simple basic content. Signature verification does not seem to require the client to submit through HTTP headers. The main reason is that I was wondering whether it could be processed uniformly at the gateway layer. This would support more algorithm implementations, and also allow authentication, authorization, signature verification and other operations to be processed directly at the gateway layer. If not, it would be rejected directly at the gateway. I re-checked the relevant content later, and it seems that it is generated and verified at the application layer, so that LLM can see the hash of the prompt. The HTTP header submission signature verification function does not seem to meet the corresponding standards, and the gateway layer seems to be only responsible for injecting unified policies. I have now re-adjusted the corresponding content, backed up the original complex design, and only initially submitted the simple implementation required for the first version

@Libres-coder
Copy link
Contributor Author

Libres-coder commented Nov 4, 2025

@johnlanni 当前网关标签注入、nonce等内容已移除,策略注入、嵌入式 Hash 验签均已完成。然后关于resource limits我想higress作为网关会不会需要在网关侧实现统一限流和保护,这样可以避免后端资源滥用,在 behaviorCertificates 中添加计数和检查逻辑就好。还是说目前初版就已经够用了,等到后续再进行设计?


@johnlanni The current gateway tag injection, nonce and other contents have been removed, and policy injection and embedded Hash signature verification have been completed. Then regarding resource limits, I wonder if higress, as a gateway, needs to implement unified current limiting and protection on the gateway side. This can avoid back-end resource abuse. Just add counting and checking logic in behaviorCertificates. Or is it that the first version is enough for now and the design will be done later?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants