diff --git a/README.md b/README.md
index 2297946e..67afaf8c 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,11 @@ Agentic ADK is an Agent application development framework launched by Alibaba In
* Offers hundreds of API tools and introduces the MCP integration gateway.
* **DeepResearch/RAG, ComputerUse, BrowserUse, Sandbox**, and other best practices for Agentic AI.
* Implementation of context extension for agent conversations, including Session, Memory, Artifact, and more, with built-in short and long-term memory plugins.
-* Provides prompt automation tuning and security risk control-related agent examples.
+* **Security and Risk Control Capabilities**:
+ * **Sensitive Word Filtering**: High-performance sensitive word detection and filtering based on DFA algorithm, supporting custom word libraries and multiple replacement strategies
+ * **Data Masking Protection**: Automatically identify and mask PII (phone numbers, ID cards, emails, bank cards, etc.) to protect user privacy
+ * **Security Callback Mechanism**: Automatically perform security checks before and after Agent execution, record security events
+ * [View Security Guide](docs/Security-Guide.md)

diff --git a/README_CN.md b/README_CN.md
index 2ab6d66a..43e98188 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -30,7 +30,11 @@ Agentic ADK 是阿里国际AI Business推出基于 [Google-ADK](https://google.g
* 提供**上百个API工具**,并推出MCP集成网关。
* **DeepResearch/RAG、ComputerUse、BrowserUse、Sandbox**等Agentic AI最佳实践。
* 智能体会话的上下文扩展实现,包括Session、Memory、Artifact等等,内置长短记忆插件。
-* 提供Prompt自动化调优、安全风控相关代理样例。
+* 提供Prompt自动化调优、**安全风控能力**:
+ * **敏感词/黑词过滤**:基于DFA算法的高性能敏感词检测和过滤,支持自定义词库和多种替换策略
+ * **数据脱敏保护**:自动识别和脱敏PII信息(手机号、身份证、邮箱、银行卡等),保护用户隐私
+ * **简单易用**:工具可独立使用,也可通过安全回调实现自动化检查
+ * [查看安全能力指南](docs/Security-Guide_CN.md) | [快速开始示例](#安全能力示例)

diff --git a/ali-agentic-adk-java/ali-agentic-adk-core/pom.xml b/ali-agentic-adk-java/ali-agentic-adk-core/pom.xml
index 2e0147b0..647e4da9 100644
--- a/ali-agentic-adk-java/ali-agentic-adk-core/pom.xml
+++ b/ali-agentic-adk-java/ali-agentic-adk-core/pom.xml
@@ -134,6 +134,54 @@
+
+
+ com.alibaba
+ ali-langengine-core
+ 1.2.6-202508111516
+
+
+
+
+ org.springframework
+ spring-context
+ ${springframework.version}
+
+
+ org.springframework
+ spring-beans
+ ${springframework.version}
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+ ${spring-boot.version}
+
+
+
+
+ org.apache.poi
+ poi
+ 5.2.3
+
+
+ org.apache.poi
+ poi-ooxml
+ 5.2.3
+
+
+ org.apache.poi
+ poi-scratchpad
+ 5.2.3
+
+
+
+
+ commons-io
+ commons-io
+ 2.11.0
+
+
com.alibaba
ali-langengine-jsonrepair
diff --git a/ali-agentic-adk-java/ali-agentic-adk-core/src/main/java/com/alibaba/agentic/core/executor/SecurityCallback.java b/ali-agentic-adk-java/ali-agentic-adk-core/src/main/java/com/alibaba/agentic/core/executor/SecurityCallback.java
new file mode 100644
index 00000000..7363865f
--- /dev/null
+++ b/ali-agentic-adk-java/ali-agentic-adk-core/src/main/java/com/alibaba/agentic/core/executor/SecurityCallback.java
@@ -0,0 +1,281 @@
+/**
+ * Copyright (C) 2024 AIDC-AI
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.agentic.core.executor;
+
+import com.alibaba.agentic.core.tools.security.DataMaskingTool;
+import com.alibaba.agentic.core.tools.security.SensitiveWordFilterTool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+/**
+ * Security callback for automated security checks.
+ *
+ * @author Libres-coder
+ * @date 2025/10/27
+ */
+public class SecurityCallback implements Callback {
+
+ private static final Logger logger = LoggerFactory.getLogger(SecurityCallback.class);
+
+ private boolean enableSensitiveWordFilter = true;
+ private boolean enableDataMasking = true;
+ private boolean blockOnSensitiveWord = false;
+ private boolean maskLogs = true;
+
+ private final SensitiveWordFilterTool sensitiveWordFilter;
+ private final DataMaskingTool dataMaskingTool;
+
+ private final List securityEvents = new ArrayList<>();
+
+ public SecurityCallback() {
+ this.sensitiveWordFilter = new SensitiveWordFilterTool();
+ this.dataMaskingTool = new DataMaskingTool();
+ }
+
+ public SecurityCallback(Set customSensitiveWords) {
+ this.sensitiveWordFilter = new SensitiveWordFilterTool(customSensitiveWords);
+ this.dataMaskingTool = new DataMaskingTool();
+ }
+
+ @Override
+ public void execute(SystemContext systemContext, Request request, Result result, CallbackChain chain) {
+ logger.debug("[SecurityCallback] Executing security checks before agent execution");
+
+ try {
+ if (request != null && request.getParam() != null) {
+ checkSecurity(request.getParam(), "REQUEST", systemContext);
+ }
+
+ chain.execute(systemContext, request, result);
+
+ } catch (SecurityException e) {
+ logger.error("[SecurityCallback] Security violation detected: {}", e.getMessage());
+ throw e;
+ }
+ }
+
+ @Override
+ public void receive(SystemContext systemContext, Request request, Result result, CallbackChain chain) {
+ logger.debug("[SecurityCallback] Executing security checks after agent execution");
+
+ try {
+ if (result != null && result.getData() != null) {
+ checkSecurity(result.getData(), "RESPONSE", systemContext);
+ }
+
+ chain.receive(systemContext, request, result);
+
+ } catch (SecurityException e) {
+ logger.error("[SecurityCallback] Security violation in response: {}", e.getMessage());
+ throw e;
+ }
+ }
+
+ private void checkSecurity(Object payload, String stage, SystemContext systemContext) {
+ if (payload == null) {
+ return;
+ }
+
+ String content = extractTextContent(payload);
+ if (content == null || content.isEmpty()) {
+ return;
+ }
+
+ if (enableSensitiveWordFilter) {
+ Map filterArgs = new HashMap<>();
+ filterArgs.put("text", content);
+ filterArgs.put("strategy", "DETECT_ONLY");
+
+ try {
+ Map filterResult = sensitiveWordFilter.run(filterArgs, systemContext)
+ .blockingFirst();
+
+ Boolean hasSensitiveWords = (Boolean) filterResult.get("has_sensitive_words");
+ if (Boolean.TRUE.equals(hasSensitiveWords)) {
+ @SuppressWarnings("unchecked")
+ List
+
+ com.alibaba
+ ali-langengine-jsonrepair
+ 1.2.6-202508111516
+ test
+
+
+ com.alibaba
+ fastjson
+
+
+ org.slf4j
+ slf4j-simple
+
+
+
+
+
+ com.alibaba
+ ali-langengine-core
+ 1.2.6-202508111516
+ test
+
+
+ org.slf4j
+ slf4j-simple
+
+
+
+
+
+
+ org.codehaus.groovy
+ groovy
+ 3.0.19
+ test
+
+
diff --git a/ali-agentic-adk-java/ali-agentic-adk-extension/ali-agentic-example/src/test/java/com/alibaba/agentic/example/SecurityAgentTest.java b/ali-agentic-adk-java/ali-agentic-adk-extension/ali-agentic-example/src/test/java/com/alibaba/agentic/example/SecurityAgentTest.java
new file mode 100644
index 00000000..bc994703
--- /dev/null
+++ b/ali-agentic-adk-java/ali-agentic-adk-extension/ali-agentic-example/src/test/java/com/alibaba/agentic/example/SecurityAgentTest.java
@@ -0,0 +1,341 @@
+package com.alibaba.agentic.example;
+
+import com.alibaba.agentic.core.executor.*;
+import com.alibaba.agentic.core.tools.security.DataMaskingTool;
+import com.alibaba.agentic.core.tools.security.SensitiveWordFilterTool;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.*;
+
+/**
+ * Security features demonstration and testing.
+ *
+ * @author Libres-coder
+ * @date 2025/10/27
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = { Application.class })
+@ActiveProfiles("testing")
+public class SecurityAgentTest {
+
+ @Test
+ public void testSensitiveWordFilter() {
+ System.out.println("\n" + "=".repeat(60));
+ System.out.println("测试1: 敏感词过滤工具");
+ System.out.println("=".repeat(60));
+
+ SensitiveWordFilterTool filterTool = new SensitiveWordFilterTool();
+ SystemContext context = new SystemContext();
+
+ // 测试用例1: 检测敏感词
+ Map args1 = new HashMap<>();
+ args1.put("text", "这是一段包含赌博和诈骗的文本内容");
+ args1.put("strategy", "DETECT_ONLY");
+
+ Map result1 = filterTool.run(args1, context).blockingFirst();
+ System.out.println("\n[检测模式]");
+ System.out.println("原始文本: " + result1.get("original_text"));
+ System.out.println("检测到敏感词: " + result1.get("has_sensitive_words"));
+ System.out.println("敏感词数量: " + result1.get("detected_words_count"));
+ System.out.println("敏感词列表: " + result1.get("detected_words"));
+
+ // 测试用例2: 星号替换
+ Map args2 = new HashMap<>();
+ args2.put("text", "我想要赌博赚快钱,有人教我诈骗");
+ args2.put("strategy", "ASTERISK");
+
+ Map result2 = filterTool.run(args2, context).blockingFirst();
+ System.out.println("\n[星号替换模式]");
+ System.out.println("原始文本: " + result2.get("original_text"));
+ System.out.println("过滤后文本: " + result2.get("filtered_text"));
+
+ // 测试用例3: 自定义替换
+ Map args3 = new HashMap<>();
+ args3.put("text", "非法内容和暴力内容不应该出现");
+ args3.put("strategy", "CUSTOM");
+ args3.put("custom_replace", "[已屏蔽]");
+
+ Map result3 = filterTool.run(args3, context).blockingFirst();
+ System.out.println("\n[自定义替换模式]");
+ System.out.println("原始文本: " + result3.get("original_text"));
+ System.out.println("过滤后文本: " + result3.get("filtered_text"));
+
+ // 测试用例4: 自定义敏感词库
+ Set customWords = new HashSet<>();
+ customWords.add("测试敏感词");
+ customWords.add("自定义词汇");
+
+ SensitiveWordFilterTool customFilter = new SensitiveWordFilterTool(customWords);
+
+ Map args4 = new HashMap<>();
+ args4.put("text", "这包含测试敏感词和自定义词汇");
+ args4.put("strategy", "ASTERISK");
+
+ Map result4 = customFilter.run(args4, context).blockingFirst();
+ System.out.println("\n[自定义词库]");
+ System.out.println("原始文本: " + result4.get("original_text"));
+ System.out.println("过滤后文本: " + result4.get("filtered_text"));
+
+ System.out.println("\n" + "=".repeat(60));
+ }
+
+ @Test
+ public void testDataMasking() {
+ System.out.println("\n" + "=".repeat(60));
+ System.out.println("测试2: 数据脱敏工具");
+ System.out.println("=".repeat(60));
+
+ DataMaskingTool maskingTool = new DataMaskingTool();
+ SystemContext context = new SystemContext();
+
+ // 测试用例1: 手机号脱敏
+ Map args1 = new HashMap<>();
+ args1.put("text", "我的手机号是13812345678,联系我吧");
+ args1.put("types", Arrays.asList("phone"));
+
+ Map result1 = maskingTool.run(args1, context).blockingFirst();
+ System.out.println("\n[手机号脱敏]");
+ System.out.println("原始文本: " + result1.get("original_text"));
+ System.out.println("脱敏后文本: " + result1.get("masked_text"));
+ System.out.println("检测到的PII: " + result1.get("detected_pii"));
+
+ // 测试用例2: 身份证号脱敏
+ Map args2 = new HashMap<>();
+ args2.put("text", "我的身份证号是110101199001011234");
+ args2.put("types", Arrays.asList("id_card"));
+
+ Map result2 = maskingTool.run(args2, context).blockingFirst();
+ System.out.println("\n[身份证号脱敏]");
+ System.out.println("原始文本: " + result2.get("original_text"));
+ System.out.println("脱敏后文本: " + result2.get("masked_text"));
+
+ // 测试用例3: 邮箱脱敏
+ Map args3 = new HashMap<>();
+ args3.put("text", "联系邮箱: user@example.com");
+ args3.put("types", Arrays.asList("email"));
+
+ Map result3 = maskingTool.run(args3, context).blockingFirst();
+ System.out.println("\n[邮箱脱敏]");
+ System.out.println("原始文本: " + result3.get("original_text"));
+ System.out.println("脱敏后文本: " + result3.get("masked_text"));
+
+ // 测试用例4: 银行卡号脱敏
+ Map args4 = new HashMap<>();
+ args4.put("text", "银行卡号: 6222021234567890123");
+ args4.put("types", Arrays.asList("bank_card"));
+
+ Map result4 = maskingTool.run(args4, context).blockingFirst();
+ System.out.println("\n[银行卡号脱敏]");
+ System.out.println("原始文本: " + result4.get("original_text"));
+ System.out.println("脱敏后文本: " + result4.get("masked_text"));
+
+ // 测试用例5: 综合测试(所有类型)
+ Map args5 = new HashMap<>();
+ args5.put("text", "用户信息: 手机13812345678,邮箱user@test.com,身份证110101199001011234");
+ args5.put("types", Arrays.asList("all"));
+
+ Map result5 = maskingTool.run(args5, context).blockingFirst();
+ System.out.println("\n[综合测试 - 所有PII类型]");
+ System.out.println("原始文本: " + result5.get("original_text"));
+ System.out.println("脱敏后文本: " + result5.get("masked_text"));
+ System.out.println("PII数量: " + result5.get("pii_count"));
+ System.out.println("检测到的PII: " + result5.get("detected_pii"));
+
+ System.out.println("\n" + "=".repeat(60));
+ }
+
+ @Test
+ public void testSecurityCallback() {
+ System.out.println("\n" + "=".repeat(60));
+ System.out.println("测试3: 安全回调处理器");
+ System.out.println("=".repeat(60));
+
+ SecurityCallback securityCallback = new SecurityCallback()
+ .enableSensitiveWordFilter(true)
+ .enableDataMasking(true)
+ .setBlockOnSensitiveWord(false)
+ .setMaskLogs(true);
+
+ securityCallback.addSensitiveWord("机密信息");
+
+ SystemContext context = new SystemContext();
+
+ // 模拟请求
+ Map requestPayload = new HashMap<>();
+ requestPayload.put("message", "我想分享一些赌博技巧和机密信息,我的手机是13812345678");
+
+ Request request = new Request()
+ .setInvokeMode(InvokeMode.SYNC)
+ .setParam(requestPayload);
+ Result result = new Result();
+
+ // 创建简单的回调链
+ CallbackChain chain = new CallbackChain() {
+ @Override
+ public void execute(SystemContext systemContext, Request request, Result result) {
+ System.out.println("\n[回调链] execute方法被调用");
+ System.out.println("请求已通过安全检查,继续执行...");
+ }
+
+ @Override
+ public void receive(SystemContext systemContext, Request request, Result result) {
+ System.out.println("\n[回调链] receive方法被调用");
+ System.out.println("响应已通过安全检查");
+ }
+ };
+
+ // 执行安全回调
+ System.out.println("\n[执行阶段安全检查]");
+ try {
+ securityCallback.execute(context, request, result, chain);
+ } catch (SecurityException e) {
+ System.out.println("安全异常: " + e.getMessage());
+ }
+
+ // 模拟响应
+ Map responsePayload = new HashMap<>();
+ responsePayload.put("message", "这是包含用户邮箱user@example.com的响应");
+ result.setData(responsePayload);
+
+ System.out.println("\n[接收阶段安全检查]");
+ try {
+ securityCallback.receive(context, request, result, chain);
+ } catch (SecurityException e) {
+ System.out.println("安全异常: " + e.getMessage());
+ }
+
+ // 查看安全事件
+ System.out.println("\n[安全事件记录]");
+ List events = securityCallback.getSecurityEvents();
+ System.out.println("记录的安全事件数量: " + events.size());
+ for (SecurityCallback.SecurityEvent event : events) {
+ System.out.println(" - " + event);
+ }
+
+ System.out.println("\n" + "=".repeat(60));
+ }
+
+ @Test
+ public void testSecurityCallbackWithBlock() {
+ System.out.println("\n" + "=".repeat(60));
+ System.out.println("测试4: 安全回调 - 阻断模式");
+ System.out.println("=".repeat(60));
+
+ // 创建启用阻断的安全回调
+ SecurityCallback securityCallback = new SecurityCallback()
+ .enableSensitiveWordFilter(true)
+ .setBlockOnSensitiveWord(true); // 启用阻断
+
+ SystemContext context = new SystemContext();
+
+ // 模拟包含敏感词的请求
+ Map requestPayload = new HashMap<>();
+ requestPayload.put("message", "我要学习诈骗技术");
+
+ Request request = new Request()
+ .setInvokeMode(InvokeMode.SYNC)
+ .setParam(requestPayload);
+ Result result = new Result();
+
+ CallbackChain chain = new CallbackChain() {
+ @Override
+ public void execute(SystemContext systemContext, Request request, Result result) {
+ System.out.println("这行不应该被打印(请求应该被阻断)");
+ }
+
+ @Override
+ public void receive(SystemContext systemContext, Request request, Result result) {
+ System.out.println("响应处理");
+ }
+ };
+
+ // 执行安全回调 - 应该抛出异常
+ System.out.println("\n[测试阻断功能]");
+ System.out.println("尝试发送包含敏感词的请求...");
+ try {
+ securityCallback.execute(context, request, result, chain);
+ System.out.println("错误: 请求没有被阻断!");
+ } catch (SecurityException e) {
+ System.out.println("成功: 请求被阻断!");
+ System.out.println("原因: " + e.getMessage());
+ }
+
+ System.out.println("\n" + "=".repeat(60));
+ }
+
+ @Test
+ public void testSecureCustomerServiceAgent() {
+ System.out.println("\n" + "=".repeat(60));
+ System.out.println("测试5: 综合示例 - 安全的客服Agent");
+ System.out.println("=".repeat(60));
+
+ // 1. 创建安全工具
+ SensitiveWordFilterTool filterTool = new SensitiveWordFilterTool();
+ DataMaskingTool maskingTool = new DataMaskingTool();
+
+ // 2. 创建安全回调
+ SecurityCallback securityCallback = new SecurityCallback()
+ .enableSensitiveWordFilter(true)
+ .enableDataMasking(true)
+ .setBlockOnSensitiveWord(false)
+ .setMaskLogs(true);
+
+ SystemContext context = new SystemContext();
+
+ // 3. 模拟客户查询
+ System.out.println("\n[场景: 客户咨询订单问题]");
+ String customerQuery = "您好,我的订单号是ORDER-123,手机号13812345678,想查询订单状态";
+
+ // 3.1 先进行敏感词检查
+ Map filterArgs = new HashMap<>();
+ filterArgs.put("text", customerQuery);
+ filterArgs.put("strategy", "DETECT_ONLY");
+
+ Map filterResult = filterTool.run(filterArgs, context).blockingFirst();
+ System.out.println("客户输入: " + customerQuery);
+ System.out.println("敏感词检测: " + (Boolean.TRUE.equals(filterResult.get("has_sensitive_words")) ? "❌ 发现敏感词" : "✅ 通过"));
+
+ // 3.2 脱敏日志记录
+ Map maskArgs = new HashMap<>();
+ maskArgs.put("text", customerQuery);
+ maskArgs.put("types", Arrays.asList("all"));
+
+ Map maskResult = maskingTool.run(maskArgs, context).blockingFirst();
+ System.out.println("日志记录(脱敏): " + maskResult.get("masked_text"));
+
+ // 4. 模拟Agent响应
+ System.out.println("\n[Agent处理并响应]");
+ String agentResponse = "您好!您的订单ORDER-123状态为已发货。" +
+ "稍后会发送短信到手机 13812345678。" +
+ "如有问题请联系客服邮箱 support@company.com";
+
+ // 4.1 响应脱敏
+ Map responseArgs = new HashMap<>();
+ responseArgs.put("text", agentResponse);
+ responseArgs.put("types", Arrays.asList("all"));
+
+ Map responseMask = maskingTool.run(responseArgs, context).blockingFirst();
+ System.out.println("原始响应: " + agentResponse);
+ System.out.println("日志记录(脱敏): " + responseMask.get("masked_text"));
+ System.out.println("检测到PII数量: " + responseMask.get("pii_count"));
+
+ // 5. 查看安全统计
+ System.out.println("\n[安全统计]");
+ System.out.println("所有敏感数据已被正确处理");
+ System.out.println("PII信息已被脱敏保护");
+ System.out.println("可以安全地记录到日志系统");
+
+ System.out.println("\n" + "=".repeat(60));
+ System.out.println("综合示例完成!");
+ System.out.println("安全措施:");
+ System.out.println("1. 输入过滤 - 检测用户输入中的敏感词");
+ System.out.println("2. PII保护 - 自动识别和脱敏个人信息");
+ System.out.println("3. 日志安全 - 记录脱敏后的数据");
+ System.out.println("4. 合规性 - 满足数据隐私保护要求");
+ System.out.println("=".repeat(60));
+ }
+}
diff --git a/ali-agentic-adk-python/examples/security_demo/__init__.py b/ali-agentic-adk-python/examples/security_demo/__init__.py
new file mode 100644
index 00000000..562e7594
--- /dev/null
+++ b/ali-agentic-adk-python/examples/security_demo/__init__.py
@@ -0,0 +1,30 @@
+# Copyright (C) 2025 AIDC-AI
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+"""
+Security Demo - 安全能力示例
+
+本模块展示如何使用安全工具保护Agent应用:
+1. 敏感词/黑词过滤
+2. 数据脱敏(PII保护)
+3. 安全的日志记录
+"""
+
+
diff --git a/ali-agentic-adk-python/examples/security_demo/security_example.py b/ali-agentic-adk-python/examples/security_demo/security_example.py
new file mode 100644
index 00000000..4cd2390b
--- /dev/null
+++ b/ali-agentic-adk-python/examples/security_demo/security_example.py
@@ -0,0 +1,316 @@
+# Copyright (C) 2025 AIDC-AI
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+"""
+Security Features Example - 安全能力示例
+
+Demonstrates how to use security tools to protect Agent applications.
+演示如何使用安全工具保护Agent应用。
+"""
+
+from ali_agentic_adk_python.core.tool.security_tools import (
+ SensitiveWordFilterTool,
+ DataMaskingTool,
+ ReplaceStrategy
+)
+
+
+def demo_sensitive_word_filter():
+ """演示敏感词过滤工具"""
+ print("\n" + "="*60)
+ print("示例1: 敏感词过滤工具")
+ print("="*60)
+
+ filter_tool = SensitiveWordFilterTool()
+
+ print("\n[检测模式]")
+ result1 = filter_tool.run(
+ text="这是一段包含赌博和诈骗的文本内容",
+ strategy="detect_only"
+ )
+ print(f"原始文本: {result1['original_text']}")
+ print(f"检测到敏感词: {result1['has_sensitive_words']}")
+ print(f"敏感词数量: {result1['detected_words_count']}")
+ print(f"敏感词列表: {result1['detected_words']}")
+
+ print("\n[星号替换模式]")
+ result2 = filter_tool.run(
+ text="我想要赌博赚快钱,有人教我诈骗",
+ strategy="asterisk"
+ )
+ print(f"原始文本: {result2['original_text']}")
+ print(f"过滤后文本: {result2['filtered_text']}")
+
+ print("\n[自定义替换模式]")
+ result3 = filter_tool.run(
+ text="非法内容和暴力内容不应该出现",
+ strategy="custom",
+ custom_replace="[已屏蔽]"
+ )
+ print(f"原始文本: {result3['original_text']}")
+ print(f"过滤后文本: {result3['filtered_text']}")
+
+ print("\n[删除模式]")
+ result4 = filter_tool.run(
+ text="这里有黄色和色情内容",
+ strategy="delete"
+ )
+ print(f"原始文本: {result4['original_text']}")
+ print(f"过滤后文本: {result4['filtered_text']}")
+
+ print("\n[自定义词库]")
+ custom_filter = SensitiveWordFilterTool({"测试敏感词", "自定义词汇"})
+ result5 = custom_filter.run(
+ text="这包含测试敏感词和自定义词汇",
+ strategy="asterisk"
+ )
+ print(f"原始文本: {result5['original_text']}")
+ print(f"过滤后文本: {result5['filtered_text']}")
+
+
+def demo_data_masking():
+ """演示数据脱敏工具"""
+ print("\n" + "="*60)
+ print("示例2: 数据脱敏工具")
+ print("="*60)
+
+ masking_tool = DataMaskingTool()
+
+ print("\n[手机号脱敏]")
+ result1 = masking_tool.run(
+ text="我的手机号是13812345678,联系我吧",
+ types=["phone"]
+ )
+ print(f"原始文本: {result1['original_text']}")
+ print(f"脱敏后文本: {result1['masked_text']}")
+ print(f"检测到的PII: {result1['detected_pii']}")
+
+ print("\n[身份证号脱敏]")
+ result2 = masking_tool.run(
+ text="我的身份证号是110101199001011234",
+ types=["id_card"]
+ )
+ print(f"原始文本: {result2['original_text']}")
+ print(f"脱敏后文本: {result2['masked_text']}")
+
+ print("\n[邮箱脱敏]")
+ result3 = masking_tool.run(
+ text="联系邮箱: user@example.com",
+ types=["email"]
+ )
+ print(f"原始文本: {result3['original_text']}")
+ print(f"脱敏后文本: {result3['masked_text']}")
+
+ print("\n[银行卡号脱敏]")
+ result4 = masking_tool.run(
+ text="银行卡号: 6222021234567890123",
+ types=["bank_card"]
+ )
+ print(f"原始文本: {result4['original_text']}")
+ print(f"脱敏后文本: {result4['masked_text']}")
+
+ print("\n[IP地址脱敏]")
+ result5 = masking_tool.run(
+ text="服务器IP是192.168.1.100",
+ types=["ip_address"]
+ )
+ print(f"原始文本: {result5['original_text']}")
+ print(f"脱敏后文本: {result5['masked_text']}")
+
+ print("\n[综合测试 - 所有PII类型]")
+ result6 = masking_tool.run(
+ text="用户信息: 手机13812345678,邮箱user@test.com,身份证110101199001011234,IP地址192.168.1.1",
+ types=["all"]
+ )
+ print(f"原始文本: {result6['original_text']}")
+ print(f"脱敏后文本: {result6['masked_text']}")
+ print(f"PII数量: {result6['pii_count']}")
+ print(f"检测到的PII: {result6['detected_pii']}")
+
+
+def demo_secure_logging():
+ """演示安全日志记录"""
+ print("\n" + "="*60)
+ print("示例3: 安全日志记录")
+ print("="*60)
+
+ masking_tool = DataMaskingTool()
+
+ log_messages = [
+ "用户登录: username=zhangsan, phone=13812345678",
+ "订单创建: order_id=ORD123, email=customer@example.com, amount=999",
+ "支付成功: card_number=6222021234567890, amount=500",
+ "错误日志: IP 192.168.1.100 访问被拒绝",
+ ]
+
+ print("\n[原始日志 vs 脱敏日志]")
+ for i, log_msg in enumerate(log_messages, 1):
+ result = masking_tool.run(text=log_msg, types=["all"])
+ print(f"\n日志{i}:")
+ print(f" 原始: {log_msg}")
+ print(f" 脱敏: {result['masked_text']}")
+ if result['has_pii']:
+ print(f" ⚠️ 检测到 {result['pii_count']} 个PII")
+
+
+def demo_secure_customer_service():
+ """演示安全的客服Agent"""
+ print("\n" + "="*60)
+ print("示例4: 安全的客服Agent")
+ print("="*60)
+
+ filter_tool = SensitiveWordFilterTool()
+ masking_tool = DataMaskingTool()
+
+ print("\n[场景: 客户咨询订单问题]")
+ customer_query = "您好,我的订单号是ORDER-123,手机号13812345678,想查询订单状态"
+
+ filter_result = filter_tool.run(
+ text=customer_query,
+ strategy="detect_only"
+ )
+ print(f"客户输入: {customer_query}")
+ print(f"敏感词检测: {'发现敏感词' if filter_result['has_sensitive_words'] else '✅ 通过'}")
+
+ mask_result = masking_tool.run(
+ text=customer_query,
+ types=["all"]
+ )
+ print(f"日志记录(脱敏): {mask_result['masked_text']}")
+
+ print("\n[Agent处理并响应]")
+ agent_response = (
+ "您好!您的订单ORDER-123状态为已发货。"
+ "稍后会发送短信到手机 13812345678。"
+ "如有问题请联系客服邮箱 support@company.com"
+ )
+
+ response_mask = masking_tool.run(
+ text=agent_response,
+ types=["all"]
+ )
+ print(f"原始响应: {agent_response}")
+ print(f"日志记录(脱敏): {response_mask['masked_text']}")
+ print(f"检测到PII数量: {response_mask['pii_count']}")
+
+ print("\n[安全统计]")
+ print("所有敏感数据已被正确处理")
+ print("PII信息已被脱敏保护")
+ print("可以安全地记录到日志系统")
+
+
+def demo_content_moderation():
+ """演示内容审核场景"""
+ print("\n" + "="*60)
+ print("示例5: 内容审核场景")
+ print("="*60)
+
+ filter_tool = SensitiveWordFilterTool()
+
+ user_contents = [
+ "这是一条正常的评论",
+ "这个产品真不错,值得推荐!",
+ "有人想一起赌博吗?",
+ "我知道诈骗的方法,私信我",
+ "非法内容,包含暴力和色情",
+ ]
+
+ print("\n[内容审核结果]")
+ approved_count = 0
+ rejected_count = 0
+
+ for i, content in enumerate(user_contents, 1):
+ result = filter_tool.run(
+ text=content,
+ strategy="detect_only"
+ )
+
+ if result['has_sensitive_words']:
+ status = "拒绝"
+ rejected_count += 1
+ details = f"(发现 {result['detected_words_count']} 个敏感词)"
+ else:
+ status = "通过"
+ approved_count += 1
+ details = ""
+
+ print(f"\n内容{i}: {content}")
+ print(f" 状态: {status} {details}")
+
+ print(f"\n[统计]")
+ print(f"通过: {approved_count}, 拒绝: {rejected_count}")
+
+
+def demo_performance():
+ """演示性能测试"""
+ print("\n" + "="*60)
+ print("示例6: 性能测试")
+ print("="*60)
+
+ import time
+
+ filter_tool = SensitiveWordFilterTool()
+ masking_tool = DataMaskingTool()
+
+ test_text = "这是一段测试文本,包含手机号13812345678,邮箱test@example.com,以及一些赌博诈骗等敏感词汇。" * 10
+
+ print("\n[敏感词过滤性能]")
+ start_time = time.time()
+ iterations = 100
+ for _ in range(iterations):
+ filter_tool.run(text=test_text, strategy="detect_only")
+ end_time = time.time()
+ print(f"执行 {iterations} 次,耗时: {(end_time - start_time):.3f} 秒")
+ print(f"平均每次: {((end_time - start_time) / iterations * 1000):.2f} 毫秒")
+
+ print("\n[数据脱敏性能]")
+ start_time = time.time()
+ for _ in range(iterations):
+ masking_tool.run(text=test_text, types=["all"])
+ end_time = time.time()
+ print(f"执行 {iterations} 次,耗时: {(end_time - start_time):.3f} 秒")
+ print(f"平均每次: {((end_time - start_time) / iterations * 1000):.2f} 毫秒")
+
+
+def main():
+ """运行所有示例"""
+ print("\n" + "="*60)
+ print("安全能力示例 - Ali Agentic ADK Python")
+ print("="*60)
+
+ demo_sensitive_word_filter()
+ demo_data_masking()
+ demo_secure_logging()
+ demo_secure_customer_service()
+ demo_content_moderation()
+ demo_performance()
+
+ print("\n" + "="*60)
+ print("所有示例完成!")
+ print("\n安全措施总结:")
+ print("1. 敏感词过滤 - 保护应用免受不当内容影响")
+ print("2. 数据脱敏 - 保护用户隐私信息")
+ print("3. 安全日志 - 合规的日志记录方式")
+ print("4. 内容审核 - 自动化的内容安全检查")
+ print("="*60 + "\n")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ali-agentic-adk-python/src/ali_agentic_adk_python/core/tool/security_tools.py b/ali-agentic-adk-python/src/ali_agentic_adk_python/core/tool/security_tools.py
new file mode 100644
index 00000000..8dbce593
--- /dev/null
+++ b/ali-agentic-adk-python/src/ali_agentic_adk_python/core/tool/security_tools.py
@@ -0,0 +1,317 @@
+# Copyright (C) 2025 AIDC-AI
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+"""
+Security Tools - 安全工具集
+
+Provides sensitive word filtering and data masking capabilities.
+提供敏感词过滤和数据脱敏能力。
+"""
+
+from typing import Dict, List, Set, Tuple, Any, Optional
+from enum import Enum
+import re
+from dataclasses import dataclass
+
+
+class ReplaceStrategy(Enum):
+ """Replace strategy for sensitive words."""
+ ASTERISK = "asterisk"
+ DELETE = "delete"
+ CUSTOM = "custom"
+ DETECT_ONLY = "detect_only"
+
+
+class PIIType(Enum):
+ """PII types for data masking."""
+ PHONE = ("phone", r"1[3-9]\d{9}", 3, 4)
+ ID_CARD = ("id_card", r"[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[0-9Xx]", 6, 4)
+ EMAIL = ("email", r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", 2, -1)
+ BANK_CARD = ("bank_card", r"\d{13,19}", 4, 4)
+ IP_ADDRESS = ("ip_address", r"(? Dict[str, Any]:
+ if not text:
+ return self._create_result(text, [], text, False)
+
+ try:
+ replace_strategy = ReplaceStrategy(strategy.lower())
+ except ValueError:
+ replace_strategy = ReplaceStrategy.ASTERISK
+
+ detected_words = self._detect_sensitive_words(text)
+ filtered_text = self._filter_text(text, detected_words, replace_strategy, custom_replace)
+
+ return self._create_result(text, detected_words, filtered_text, len(detected_words) > 0)
+
+ def _detect_sensitive_words(self, text: str) -> List[SensitiveWordResult]:
+ results = []
+ i = 0
+
+ while i < len(text):
+ length = self._check_sensitive_word(text, i)
+ if length > 0:
+ word = text[i:i + length]
+ results.append(SensitiveWordResult(word, i, i + length))
+ i += length
+ else:
+ i += 1
+
+ return results
+
+ def _check_sensitive_word(self, text: str, start_index: int) -> int:
+ match_length = 0
+ current_map = self.sensitive_word_map
+
+ for i in range(start_index, len(text)):
+ char = text[i]
+
+ if char not in current_map:
+ break
+
+ match_length += 1
+
+ if "END" in current_map[char]:
+ return match_length # 找到完整敏感词
+
+ current_map = current_map[char]
+
+ return 0
+
+ def _filter_text(self, text: str, detected_words: List[SensitiveWordResult],
+ strategy: ReplaceStrategy, custom_replace: str) -> str:
+ if not detected_words or strategy == ReplaceStrategy.DETECT_ONLY:
+ return text
+
+ result = list(text)
+ offset = 0
+
+ for word in detected_words:
+ start = word.start_index + offset
+ end = word.end_index + offset
+
+ if strategy == ReplaceStrategy.ASTERISK:
+ replacement = "*" * len(word.word)
+ elif strategy == ReplaceStrategy.DELETE:
+ replacement = ""
+ elif strategy == ReplaceStrategy.CUSTOM:
+ replacement = custom_replace
+ else:
+ replacement = word.word
+
+ result[start:end] = replacement
+ offset += len(replacement) - len(word.word)
+
+ return "".join(result)
+
+ def _create_result(self, original_text: str, detected_words: List[SensitiveWordResult],
+ filtered_text: str, has_sensitive_words: bool) -> Dict[str, Any]:
+ return {
+ "original_text": original_text,
+ "filtered_text": filtered_text,
+ "has_sensitive_words": has_sensitive_words,
+ "detected_words_count": len(detected_words),
+ "detected_words": [
+ {
+ "word": word.word,
+ "start_index": word.start_index,
+ "end_index": word.end_index
+ }
+ for word in detected_words
+ ]
+ }
+
+ def add_sensitive_word(self, word: str):
+ self._init_sensitive_word_map({word})
+
+ def add_sensitive_words(self, words: Set[str]):
+ self._init_sensitive_word_map(words)
+
+ @staticmethod
+ def _get_default_sensitive_words() -> Set[str]:
+ return {
+ "政治敏感", "反动", "暴力",
+ "色情", "黄色", "裸体",
+ "赌博", "赌场", "赌钱",
+ "毒品", "枪支", "爆炸物",
+ "诈骗", "骗钱", "传销",
+ "恐怖主义", "邪教", "非法",
+ }
+
+
+class DataMaskingTool:
+ """Data masking tool for PII protection."""
+
+ def run(self, text: str, types: List[str] = None,
+ mask_char: str = "*") -> Dict[str, Any]:
+ if not text:
+ return self._create_result(text, text, [])
+
+ if types is None:
+ types = ["all"]
+
+ types_to_check = self._determine_types(types)
+
+ masked_text, detected_pii = self._mask_text(text, types_to_check, mask_char)
+
+ return self._create_result(text, masked_text, detected_pii)
+
+ def _determine_types(self, enabled_types: List[str]) -> List[PIIType]:
+ if "all" in enabled_types:
+ return list(PIIType)
+
+ types = []
+ for type_str in enabled_types:
+ for pii_type in PIIType:
+ if pii_type.type_name == type_str.lower():
+ types.append(pii_type)
+ break
+
+ return types
+
+ def _mask_text(self, text: str, types: List[PIIType],
+ mask_char: str) -> Tuple[str, List[PIIDetection]]:
+ masked_text = text
+ detected_pii = []
+
+ for pii_type in types:
+ matches = list(pii_type.pattern.finditer(masked_text))
+
+ for match in matches:
+ original = match.group()
+ start, end = match.span()
+
+ if pii_type == PIIType.PASSWORD and match.lastindex >= 2:
+ original = match.group(2)
+ masked = match.group(1) + re.sub(r'[^"\':=\s]', mask_char,
+ match.group(0)[len(match.group(1)):])
+ else:
+ masked = self._mask_string(original, pii_type.prefix_keep,
+ pii_type.suffix_keep, mask_char)
+
+ detection = PIIDetection(
+ pii_type=pii_type.type_name,
+ original_value=original,
+ masked_value=masked,
+ start_index=start,
+ end_index=end
+ )
+ detected_pii.append(detection)
+
+ masked_text = masked_text[:start] + masked + masked_text[end:]
+
+ return masked_text, detected_pii
+
+ def _mask_string(self, text: str, prefix_keep: int, suffix_keep: int,
+ mask_char: str) -> str:
+ if not text:
+ return text
+
+ length = len(text)
+
+ if suffix_keep == -1 and "@" in text:
+ parts = text.split("@")
+ if len(parts) == 2:
+ local_part = parts[0]
+ keep_length = min(prefix_keep, len(local_part) // 2)
+ masked_local = local_part[:keep_length] + mask_char * max(len(local_part) - keep_length, 3)
+ return masked_local + "@" + parts[1]
+
+ if prefix_keep == -1 and suffix_keep == -1:
+ return mask_char * min(length, 10)
+
+ if length <= prefix_keep + suffix_keep:
+ return mask_char * length
+
+ prefix = text[:prefix_keep]
+ suffix = text[-suffix_keep:]
+ mask_length = length - prefix_keep - suffix_keep
+
+ return prefix + mask_char * mask_length + suffix
+
+ def _create_result(self, original_text: str, masked_text: str,
+ detected_pii: List[PIIDetection]) -> Dict[str, Any]:
+ return {
+ "original_text": original_text,
+ "masked_text": masked_text,
+ "has_pii": len(detected_pii) > 0,
+ "pii_count": len(detected_pii),
+ "detected_pii": [
+ {
+ "type": pii.pii_type,
+ "original_value": pii.original_value,
+ "masked_value": pii.masked_value,
+ "start_index": pii.start_index,
+ "end_index": pii.end_index
+ }
+ for pii in detected_pii
+ ]
+ }