Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

![Architecture Diagram](https://zos-oss-ol.oss-cn-hangzhou.aliyuncs.com/data/be03cd4383682bd6e8095ebf8472a0d1.png)

Expand Down
6 changes: 5 additions & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) | [快速开始示例](#安全能力示例)

![架构图](https://zos-oss-ol.oss-cn-hangzhou.aliyuncs.com/data/be03cd4383682bd6e8095ebf8472a0d1.png)

Expand Down
48 changes: 48 additions & 0 deletions ali-agentic-adk-java/ali-agentic-adk-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,54 @@
</exclusions>
</dependency>

<!-- Ali-LangEngine Core dependency for Document and other classes -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>ali-langengine-core</artifactId>
<version>1.2.6-202508111516</version>
</dependency>

<!-- Spring Framework dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring-boot.version}</version>
</dependency>

<!-- Apache POI for Office document processing -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>5.2.3</version>
</dependency>

<!-- Apache Commons IO -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>ali-langengine-jsonrepair</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -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<SecurityEvent> securityEvents = new ArrayList<>();

public SecurityCallback() {
this.sensitiveWordFilter = new SensitiveWordFilterTool();
this.dataMaskingTool = new DataMaskingTool();
}

public SecurityCallback(Set<String> 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<String, Object> filterArgs = new HashMap<>();
filterArgs.put("text", content);
filterArgs.put("strategy", "DETECT_ONLY");

try {
Map<String, Object> filterResult = sensitiveWordFilter.run(filterArgs, systemContext)
.blockingFirst();

Boolean hasSensitiveWords = (Boolean) filterResult.get("has_sensitive_words");
if (Boolean.TRUE.equals(hasSensitiveWords)) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> detectedWords =
(List<Map<String, Object>>) filterResult.get("detected_words");

SecurityEvent event = new SecurityEvent(
SecurityEventType.SENSITIVE_WORD_DETECTED,
stage,
"Detected " + detectedWords.size() + " sensitive word(s)",
detectedWords
);
securityEvents.add(event);

logger.warn("[SecurityCallback] {} - Sensitive words detected: {}",
stage, detectedWords.size());

if (blockOnSensitiveWord) {
SecurityException secEx = new SecurityException(
"Sensitive word detected in " + stage + ". Request blocked.");
logger.error("[SecurityCallback] {}", secEx.getMessage());
throw secEx;
}
}
} catch (SecurityException e) {
throw e;
} catch (Exception e) {
logger.error("[SecurityCallback] Error during sensitive word filter: {}", e.getMessage());
}
}

if (enableDataMasking) {
Map<String, Object> maskArgs = new HashMap<>();
maskArgs.put("text", content);
maskArgs.put("types", Arrays.asList("all"));

try {
Map<String, Object> maskResult = dataMaskingTool.run(maskArgs, systemContext)
.blockingFirst();

Boolean hasPII = (Boolean) maskResult.get("has_pii");
if (Boolean.TRUE.equals(hasPII)) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> detectedPII =
(List<Map<String, Object>>) maskResult.get("detected_pii");

SecurityEvent event = new SecurityEvent(
SecurityEventType.PII_DETECTED,
stage,
"Detected " + detectedPII.size() + " PII item(s)",
detectedPII
);
securityEvents.add(event);

logger.warn("[SecurityCallback] {} - PII detected: {}", stage, detectedPII.size());

if (maskLogs) {
String maskedText = (String) maskResult.get("masked_text");
logger.debug("[SecurityCallback] Masked content: {}", maskedText);
}
}
} catch (Exception e) {
logger.error("[SecurityCallback] Error during data masking: {}", e.getMessage());
}
}
}

private String extractTextContent(Object payload) {
if (payload instanceof String) {
return (String) payload;
} else if (payload instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) payload;

for (String key : Arrays.asList("text", "content", "message", "prompt", "response")) {
Object value = map.get(key);
if (value instanceof String) {
return (String) value;
}
}

return map.toString();
} else {
return payload.toString();
}
}

public SecurityCallback enableSensitiveWordFilter(boolean enable) {
this.enableSensitiveWordFilter = enable;
return this;
}

public SecurityCallback enableDataMasking(boolean enable) {
this.enableDataMasking = enable;
return this;
}

public SecurityCallback setBlockOnSensitiveWord(boolean block) {
this.blockOnSensitiveWord = block;
return this;
}

public SecurityCallback setMaskLogs(boolean mask) {
this.maskLogs = mask;
return this;
}

public SecurityCallback addSensitiveWord(String word) {
this.sensitiveWordFilter.addSensitiveWord(word);
return this;
}

public SecurityCallback addSensitiveWords(Set<String> words) {
this.sensitiveWordFilter.addSensitiveWords(words);
return this;
}

public List<SecurityEvent> getSecurityEvents() {
return new ArrayList<>(securityEvents);
}

public void clearSecurityEvents() {
securityEvents.clear();
}

public enum SecurityEventType {
SENSITIVE_WORD_DETECTED,
PII_DETECTED,
SECURITY_VIOLATION
}

public static class SecurityEvent {
private final SecurityEventType type;
private final String stage;
private final String message;
private final List<Map<String, Object>> details;
private final long timestamp;

public SecurityEvent(SecurityEventType type, String stage, String message,
List<Map<String, Object>> details) {
this.type = type;
this.stage = stage;
this.message = message;
this.details = details;
this.timestamp = System.currentTimeMillis();
}

public SecurityEventType getType() {
return type;
}

public String getStage() {
return stage;
}

public String getMessage() {
return message;
}

public List<Map<String, Object>> getDetails() {
return details;
}

public long getTimestamp() {
return timestamp;
}

@Override
public String toString() {
return String.format("[%s] %s - %s: %s",
new Date(timestamp), type, stage, message);
}
}
}
Loading