Skip to main content

agentsec_core/web/sanitize/
wrap.rs

1//! Wrap sanitized content into an `<untrusted_content>` envelope.
2//!
3//! The envelope is the contract between AgentSec and the caller LLM: text
4//! inside the envelope is treated as **data, not instruction**. The
5//! attributes carry provenance metadata so the LLM can reason about where
6//! the content came from and what was already stripped.
7
8use chrono::Utc;
9
10/// Wrap `body` in an `<untrusted_content>` element with provenance
11/// attributes.
12///
13/// Schema:
14///
15/// ```xml
16/// <untrusted_content
17///   src="<url>"
18///   sanitized_at="<RFC 3339 UTC>"
19///   removed_patterns="<comma-separated pattern labels>">
20/// <body...>
21/// </untrusted_content>
22/// ```
23///
24/// `removed` may be empty; the attribute is still emitted as an empty
25/// string so downstream parsers can rely on the schema being uniform.
26pub fn envelope(url: &str, body: &str, removed: &[String]) -> String {
27    let ts = Utc::now().to_rfc3339();
28    let removed_attr = removed.join(",");
29    format!(
30        "<untrusted_content src=\"{url}\" sanitized_at=\"{ts}\" removed_patterns=\"{removed_attr}\">\n{body}\n</untrusted_content>"
31    )
32}