Json.Masker is a lightweight library for masking sensitive values during JSON serialization.
Mark properties with [Sensitive], enable the masking context, and the rest happens automatically—no custom DTOs or fragile string hacks.
Supports both Newtonsoft.Json and System.Text.Json.
| Package | Description |
|---|---|
| Json.Masker.Abstract | Shared abstractions: [Sensitive] attribute, masking strategies, context accessors, and DefaultMaskingService. Not published to NuGet. |
| Json.Masker.Newtonsoft | ContractResolver that wraps sensitive members before serialization. |
| Json.Masker.SystemTextJson | JsonTypeInfo modifier that injects masking converters for System.Text.Json. |
| Json.Masker.AspNet | Middleware and helpers for toggling masking per request (System.Text.Json). |
| Json.Masker.AspNet.Newtonsoft | ASP.NET Core middleware integration for Newtonsoft.Json. |
Install the package for your serializer:
dotnet add package Json.Masker.Newtonsoft
# or
dotnet add package Json.Masker.SystemTextJson
# optional ASP.NET helpers
dotnet add package Json.Masker.AspNet
dotnet add package Json.Masker.AspNet.NewtonsoftThe ASP.NET helpers let you toggle masking per request with zero boilerplate.
builder.Services.AddJsonMasking(options =>
{
// Replace with a custom IMaskingService if needed
options.MaskingService = new DefaultMaskingService();
});
builder.Services
.AddOptions<MvcNewtonsoftJsonOptions>()
.Configure<IJsonMaskingConfigurator>((opts, configurator) =>
configurator.Configure(opts.SerializerSettings));
app.UseNewtonsoftJsonMasking();Swap Newtonsoft for System.Text.Json as needed:
builder.Services.AddControllers();
builder.Services.AddJsonMasking();
builder.Services
.AddOptions<JsonOptions>()
.Configure<IJsonMaskingConfigurator>((opts, configurator) =>
configurator.Configure(opts.SerializerOptions));
app.UseTextJsonMasking();DI automatically registers:
IMaskingService(default or custom)IJsonMaskingConfigurator(serializer-specific configurator)
Newtonsoft.Json
var masking = new DefaultMaskingService();
var settings = new JsonSerializerSettings
{
ContractResolver = new MaskingContractResolver(masking)
};
var json = JsonConvert.SerializeObject(customer, Formatting.Indented, settings);System.Text.Json
var masking = new DefaultMaskingService();
var options = new JsonSerializerOptions
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver
{
Modifiers = { new MaskingTypeInfoModifier(masking).Modify }
}
};
var json = JsonSerializer.Serialize(customer, options);public class Customer
{
public string Name { get; set; } = string.Empty;
[Sensitive(MaskingStrategy.Creditcard)]
public string CreditCard { get; set; } = string.Empty;
[Sensitive(MaskingStrategy.Ssn)]
public string SSN { get; set; } = string.Empty;
[Sensitive(MaskingStrategy.Email)]
public string Email { get; set; } = string.Empty;
[Sensitive(MaskingStrategy.Iban)]
public string BankAccount { get; set; } = string.Empty;
[Sensitive] public int Age { get; set; }
[Sensitive(MaskingStrategy.Redacted)]
public List<string> Hobbies { get; set; } = [];
[Sensitive("##-****-####")]
public string LoyaltyNumber { get; set; } = string.Empty;
}Enable masking for the current scope:
MaskingContextAccessor.Set(new MaskingContext { Enabled = true });Result:
{
"Name": "Alice",
"CreditCard": "****-****-****-1234",
"SSN": "***-**-6789",
"Email": "a*****@g****.com",
"BankAccount": "GB** **** **** **** 1234",
"Age": "****",
"Hobbies": ["<redacted>", "<redacted>"],
"LoyaltyNumber": "12-****-3456"
}| Strategy | Example Output |
|---|---|
Default |
**** |
Creditcard |
****-****-****-1234 |
Ssn |
***-**-6789 |
Redacted |
<redacted> |
Email |
a*****@d****.com |
Iban |
GB** **** **** **** 1234 |
Custom masking logic? Implement IMaskingService and register it via MaskingOptions.
dotnet restore,dotnet build,dotnet test- Run
./install-dependencies.shto sync the expected .NET SDK and git hooks. - Run
./run-pre-commit.shto check analyzers and formatters. - Open a PR with conventional commits; merging to
maintriggers NuGet release.
To add a new masking rule:
- Implement
IMaskingServiceor subclassDefaultMaskingService. - Add tests under
tests/Json.Masker.Tests. - (Optional) Contribute back via a new
MaskingStrategyvalue.
To integrate another serializer:
- Create a project under
src/referencingJson.Masker.Abstract. - Implement
IJsonMaskingConfigurator. - Expose an
AddJsonMaskingextension. - Add integration tests to ensure sensitive data is masked.
| Method | Mean | Allocated | Ratio |
|---|---|---|---|
| Plain_SystemTextJson | 501 ns | 752 B | 1.00 |
| JsonMasker_Newtonsoft | 990 ns | 2,152 B | 1.97 |
| JsonMasker_SystemTextJson | 801 ns | 648 B | 1.62 |
| JsonDataMasking_Newtonsoft | 8,085 ns | 6,761 B | 16.08 |
| JsonMasking_PayloadMasking | 7,013 ns | 5,720 B | 13.90 |
| Byndyusoft_SystemTextJson | 324 ns | 232 B | 0.64 |
dotnet restore
dotnet build
dotnet testRun ./install-dependencies.sh to install matching SDKs and pre-commit hooks.
Check out /samples for minimal demos:
- System.Text.Json:
Json.Masker.Sample.SystemTextJson - Newtonsoft.Json:
Json.Masker.Sample.Newtonsoft
Run with:
dotnet run --project <sample-project>View masked and unmasked outputs side-by-side in your favorite REST client. Note: in order to see masked output make sure to include 'X-Json-Mask: true' in the request headers.