Skip to content

Commit 5afec33

Browse files
committed
added question 17 to the Artificial Intelligence Questions
1 parent b24382a commit 5afec33

1 file changed

Lines changed: 146 additions & 1 deletion

File tree

Lines changed: 146 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,146 @@
1-
# AI - Question 17 - From a C# backend perspective, what patterns would you use to sanitize user inputs before they are injected into a ChatHistory object?
1+
# AI - Question 17 - From a C# backend perspective, what patterns would you use to sanitize user inputs before they are injected into a ChatHistory object?
2+
3+
**From a C# backend perspective**, sanitizing user inputs before adding them to a `ChatHistory` object (in `Microsoft.Extensions.AI` or Semantic Kernel) is critical for security (prompt injection), safety (toxic/harmful content), and reliability (token limits, stability).
4+
5+
### Recommended Defense-in-Depth Patterns
6+
7+
1. **Input Validation & Normalization** (Fast, always-on)
8+
2. **Content Safety Moderation** (Azure AI Content Safety or local alternatives)
9+
3. **Prompt Injection Hardening**
10+
4. **Length & Token Control**
11+
5. **Logging & Auditing** (without storing raw PII)
12+
13+
**Sanitization Pipeline**
14+
```mermaid
15+
flowchart TD
16+
A[Raw User Input] --> B["Basic Validation<br>(Length, Format, Encoding)"]
17+
B --> C["Content Safety Check<br>(Azure AI Content Safety)"]
18+
C --> D{Pass?}
19+
D -->|No| E[Reject + User Feedback]
20+
D -->|Yes| F["Prompt Hardening<br>(System Instructions + Escaping)"]
21+
F --> G["Token Estimation<br>+ Truncation"]
22+
G --> H[Add to ChatHistory]
23+
24+
style B fill:#90EE90
25+
style C fill:#90EE90
26+
style F fill:#90EE90
27+
```
28+
29+
### Production-Ready Implementation
30+
```csharp
31+
using Microsoft.Extensions.AI;
32+
using Azure.AI.ContentSafety; // Or equivalent
33+
34+
public class ChatHistorySanitizer
35+
{
36+
private readonly ContentSafetyClient? _safetyClient;
37+
private readonly int _maxInputLength = 4000;
38+
private readonly int _maxTokens = 800;
39+
40+
public ChatHistorySanitizer(ContentSafetyClient? safetyClient = null)
41+
{
42+
_safetyClient = safetyClient;
43+
}
44+
45+
public async Task<ChatMessage> SanitizeAndCreateMessageAsync(
46+
string userInput,
47+
ChatRole role = ChatRole.User,
48+
CancellationToken ct = default)
49+
{
50+
// 1. Basic validation
51+
if (string.IsNullOrWhiteSpace(userInput))
52+
throw new ArgumentException("Input cannot be empty.");
53+
54+
if (userInput.Length > _maxInputLength)
55+
userInput = userInput[.._maxInputLength];
56+
57+
// Normalize
58+
userInput = userInput.Trim().Replace("\r\n", "\n");
59+
60+
// 2. Content Safety Moderation
61+
if (_safetyClient != null)
62+
{
63+
var request = new AnalyzeTextOptions(userInput);
64+
var response = await _safetyClient.AnalyzeTextAsync(request, ct);
65+
66+
if (IsHarmfulContent(response))
67+
{
68+
throw new InvalidOperationException("Input violates safety policies.");
69+
}
70+
}
71+
72+
// 3. Prompt Injection Defense
73+
userInput = HardenAgainstInjection(userInput);
74+
75+
// 4. Optional: Token estimation + truncation
76+
userInput = TruncateToTokenLimit(userInput, _maxTokens);
77+
78+
return new ChatMessage(role, userInput);
79+
}
80+
81+
private static bool IsHarmfulContent(AnalyzeTextResult result)
82+
{
83+
// Example thresholds - tune based on your policy
84+
return result.HateResult?.Severity > ContentSeverityLevel.Medium ||
85+
result.SexualResult?.Severity > ContentSeverityLevel.Medium ||
86+
result.ViolenceResult?.Severity > ContentSeverityLevel.Medium ||
87+
result.SelfHarmResult?.Severity > ContentSeverityLevel.Medium;
88+
}
89+
90+
private static string HardenAgainstInjection(string input)
91+
{
92+
// Simple but effective techniques
93+
return input
94+
.Replace("{", "{{")
95+
.Replace("}", "}}")
96+
.Replace("[", "[[")
97+
.Replace("]", "]]");
98+
// More advanced: use delimiters or system prompt instructions
99+
}
100+
101+
private string TruncateToTokenLimit(string text, int maxTokens)
102+
{
103+
// Rough estimation (can use real tokenizer for precision)
104+
if (text.Length > maxTokens * 4)
105+
return text[..(maxTokens * 4)];
106+
107+
return text;
108+
}
109+
}
110+
```
111+
112+
### Usage in Services
113+
```csharp
114+
public class RagChatService
115+
{
116+
private readonly IChatClient _chatClient;
117+
private readonly ChatHistorySanitizer _sanitizer;
118+
119+
public async Task<string> GetResponseAsync(string userMessage)
120+
{
121+
var sanitizedMessage = await _sanitizer.SanitizeAndCreateMessageAsync(userMessage);
122+
123+
var history = new ChatHistory();
124+
history.AddSystemMessage("You are a helpful assistant..."); // Strong system prompt
125+
history.Add(sanitizedMessage);
126+
127+
var response = await _chatClient.GetResponseAsync(history);
128+
return response.Message.Text ?? string.Empty;
129+
}
130+
}
131+
```
132+
133+
### Additional Recommended Patterns
134+
- **Register as Scoped Service** in DI for easy testing and configuration.
135+
- **Combine with Semantic Kernel**: Use `KernelFunction` attributes with input descriptions and validation.
136+
- **Rate Limiting**: Apply per-user/IP limits before sanitization.
137+
- **Audit Logging**: Log sanitized metadata (length, safety score) but not raw user input if sensitive.
138+
- **Fallback**: Always have a "safe mode" that rejects high-risk inputs gracefully.
139+
140+
**Key Benefits**:
141+
- Prevents prompt injection attacks
142+
- Complies with responsible AI policies
143+
- Maintains consistent token usage and cost control
144+
- Keeps business logic clean and decoupled
145+
146+
This layered approach follows Microsoft security and responsible AI best practices for production .NET AI applications using `Microsoft.Extensions.AI` and Semantic Kernel. For the highest security, always combine technical controls with a strong system prompt and continuous monitoring. Refer to Azure AI Content Safety documentation for the latest moderation capabilities.

0 commit comments

Comments
 (0)