Sanitize Tags Unicode Block at prompt level (#4047)

This commit is contained in:
Amed Rodriguez
2025-08-15 09:12:05 -07:00
committed by GitHub
parent 85963689ce
commit 6e022a974a
3 changed files with 166 additions and 30 deletions
+54
View File
@@ -1,4 +1,19 @@
use tokio_util::sync::CancellationToken;
use unicode_normalization::UnicodeNormalization;
/// Sanitize Unicode Tags Block characters from text
/// Used to prevent Unicode-based prompt injection attacks
///
/// This function removes invisible Unicode Tags Block characters (U+E0000-U+E007F)
/// that can be used for steganographic attacks while preserving legitimate Unicode.
pub fn sanitize_unicode_tags(text: &str) -> String {
let normalized: String = text.nfc().collect();
normalized
.chars()
.filter(|&c| !matches!(c, '\u{E0000}'..='\u{E007F}'))
.collect()
}
/// Safely truncate a string at character boundaries, not byte boundaries
///
@@ -30,6 +45,45 @@ pub fn is_token_cancelled(cancellation_token: &Option<CancellationToken>) -> boo
mod tests {
use super::*;
#[test]
fn test_sanitize_unicode_tags() {
// Test that Unicode Tags Block characters are removed
let malicious = "Hello\u{E0041}\u{E0042}\u{E0043}world"; // Invisible "ABC"
let cleaned = sanitize_unicode_tags(malicious);
assert_eq!(cleaned, "Helloworld");
}
#[test]
fn test_sanitize_unicode_tags_preserves_legitimate_unicode() {
// Test that legitimate Unicode characters are preserved
let clean_text = "Hello world 世界 🌍";
let cleaned = sanitize_unicode_tags(clean_text);
assert_eq!(cleaned, clean_text);
}
#[test]
fn test_sanitize_unicode_tags_empty_string() {
let empty = "";
let cleaned = sanitize_unicode_tags(empty);
assert_eq!(cleaned, "");
}
#[test]
fn test_sanitize_unicode_tags_only_malicious() {
// Test string containing only Unicode Tags characters
let only_malicious = "\u{E0041}\u{E0042}\u{E0043}";
let cleaned = sanitize_unicode_tags(only_malicious);
assert_eq!(cleaned, "");
}
#[test]
fn test_sanitize_unicode_tags_mixed_content() {
// Test mixed legitimate and malicious Unicode
let mixed = "Hello\u{E0041} 世界\u{E0042} 🌍\u{E0043}!";
let cleaned = sanitize_unicode_tags(mixed);
assert_eq!(cleaned, "Hello 世界 🌍!");
}
#[test]
fn test_safe_truncate_ascii() {
assert_eq!(safe_truncate("hello world", 20), "hello world");