serde_mask
Mask sensitive data during serde serialization for LLM ingestion.
The derive macro generates a mask() method that returns a Masked<T> wrapper. The wrapper serializes with sensitive fields replaced by placeholders, and provides a deanonymize() method to restore original values in LLM responses.
Usage
use Anonymize;
let q = Query ;
let masked = q.mask;
// Serializes with secret masked
let json = to_string.unwrap;
// {"username":"ANON_aBcDeFgHiJ","public":"visible"}
// LLM responds with something like "Contact user ANON_aBcDeFgHiJ immediately."
// then we deanonymize it back to "Contact user my_secret_username immediately."
let response = "Contact user ANON_aBcDeFgHiJ immediately.";
let restored = masked.deanonymize;
// "Contact user my_secret_username immediately."
Supported types
#[anon] works on fields of the following types out of the box:
String- Integer types (
u8,u16,u32,u64,u128,i8,i16,i32,i64,i128,usize,isize) f32,f64boolOption<T>,Vec<T>,HashMap<K, V>where the inner types implementAnonymizeTrait
Custom types
Implement AnonymizeTrait for your own types:
use ;
;
Caveats
Numeric and boolean anonymization
Anonymization of numeric types (u8, i32, f64, etc.) and bool works via string replacement on the serialized output. This means:
- Substring collisions: a fake value like
3could match other occurrences of3in the JSON (inside field names, other numbers, etc.). String fields avoid this thanks to theANON_prefix, but numeric fields have no such prefix. - Small type ranges: types like
u8orboolhave very few possible values, increasing the chance of the fake value equaling the real one. - Type invariant breaking: numeric fields get replaced at the string level. For JSON this means an integer field might briefly appear as a different integer, which is generally fine for LLM consumption but would break strict schema validation.
For high-reliability use cases, prefer anonymizing string fields or implementing a custom AnonymizeTrait that maps values to prefixed string placeholders.