XKit.Redactor.Implementation 0.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package XKit.Redactor.Implementation --version 0.1.0
                    
NuGet\Install-Package XKit.Redactor.Implementation -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="XKit.Redactor.Implementation" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="XKit.Redactor.Implementation" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="XKit.Redactor.Implementation" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add XKit.Redactor.Implementation --version 0.1.0
                    
#r "nuget: XKit.Redactor.Implementation, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package XKit.Redactor.Implementation@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=XKit.Redactor.Implementation&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=XKit.Redactor.Implementation&version=0.1.0
                    
Install as a Cake Tool

XKit.Redactor

One contract for taking secrets out of text before it goes somewhere it cannot be recalled from - a log file, a notification, an admin page - and two ways of finding them.

Package Targets What is in it
XKit.Redactor netstandard2.0, netstandard2.1, net8.0, net9.0, net10.0 IRedactor, RedactorOptions, RedactionMode, the rule-based CredentialRedactor, Mask() and Redact(secret) string helpers
XKit.Redactor.Implementation net8.0, net9.0, net10.0 EntropyRedactor - finds secrets by how random they look, with an embedded English + developer word list

The contract

public interface IRedactor
{
	[return: NotNullIfNotNull(nameof(value))]
	string? Redact(string? value, RedactorOptions? options = null);
}

public class RedactorOptions
{
	public string? Key { get; set; }                              // where the value was found - a config key, a header name; a hint, not a decision
	public RedactionMode Mode { get; set; } = RedactionMode.Erase; // Erase: nothing survives. Mask: up to 3 characters per end survive
	public string MaskToken { get; set; } = "●●●●●●●●";           // fixed width on purpose - never leaks the length
}

The key-shaped call redactor.Redact(value, "Some:Key") is an extension method and keeps working.

Null and empty

Mode Redact(null) Redact("")
Erase (default) mask token mask token
Mask null ""

Erase never says whether there was anything, so a log line cannot be read to mean "this one is not configured". Mask already reveals something about every secret it touches, so revealing that there was none is consistent with it.

Mask never applies to a composite span

Mask reveals both ends of whatever it is given. That is safe on a value that is entirely a secret - a token, a GUID, a password on its own - and unsafe on anything that merely contains one: user:password masked would reveal the password's last characters. Every rule in this repo declares whether its captured span is isolated, and a composite span erases in every mode. Do not lose this when adding a rule.

Which redactor

CredentialRedactor (in XKit.Redactor) is cheap: three compiled regexes for the shapes a credential is usually found in - scheme://user:password@host, password= / pwd= pairs, and credential-named keys in JSON. Host, database and everything else stay readable. When no rule fires and Key reads as a credential name, the whole value is hidden. This is the one to put inside a log sink.

EntropyRedactor (in XKit.Redactor.Implementation) finds secrets of unknown shape. Each alphanumeric token is split on case transitions, the pieces in the dictionary are dropped, dictionary words that ran together in one case are stripped, and the Shannon entropy of what is left decides. GUIDs and URI passwords are always hidden; hex-looking tokens are measured as bytes; a mostly-hidden base64 value collapses to one token. A credential-shaped Key lowers the threshold from 3.3 to 2.9 rather than deciding outright. Build the WordDictionary once and share it:

services.AddSingleton(new WordDictionary(["poloniex", "apextroid"])); // product names would otherwise read as random
services.AddSingleton<IRedactor, EntropyRedactor>();

String helpers

apiKey.Mask();                          // "abc●●●●●●●●xyz" - the whole value must be the secret
message.Redact(connectionString);       // erases a known secret, and its password on its own, wherever the text quotes them

Mask() reveals nothing at 8 characters or fewer, one per end at 9-10, two at 11-12, three from 13 up. Null and empty come back unchanged, the way RedactionMode.Mask treats them.

Not covered

Microsoft.Extensions.Http's RedactLoggedHeaders runs inside the HttpClient logging handler, upstream of anything an IRedactor can see. Configure it with the header names that carry credentials; an empty list logs them all.

Building

dotnet test XKit.Redactor.slnx

Publishing is manual: bump <Version> in both csproj files, then

dotnet pack XKit.Redactor.slnx -c Release

and dotnet nuget push the two .nupkg files.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.0 98 9/20/2026
0.2.0 82 9/20/2026
0.1.0 80 9/20/2026