A thread-safe, zero-dependency Go package for detecting and masking sensitive data in logs, API responses, and configuration dumps.
- π Multiple masking strategies: Full redaction, partial masking, SHA256 hashing, or passthrough
- π³ Recursive processing: Automatically handles nested
map[string]any,[]any, and slices - π¦ JSON integration: Drop-in
json.Marshalreplacement &SensitiveValuewrapper for automatic masking - ποΈ Environment presets:
Strict(prod),Audit(logging),Debug(development) - β Validated configuration: Atomic updates with runtime validation
- π§΅ Thread-safe:
sync.RWMutexprotection for all config mutations - π« Zero dependencies: Pure standard library
- π Backward compatible: Simple
IsSensitive/RedactAPI still works
go get github.com/sudoki2015/sensitivepackage main
import (
"fmt"
"github.com/sudoki2015/sensitive"
)
func main() {
// 1. Apply a preset for your environment
_ = sensitive.ApplyPreset(sensitive.PresetStrict)
// 2. Mask individual values
fmt.Println(sensitive.MaskValue("password", "SuperSecret123"))
// β [REDACTED]
fmt.Println(sensitive.MaskValue("email", "alice@example.com"))
// β al********@example.com
// 3. Mask complex structures recursively
data := map[string]any{
"user": "alice",
"password": "secret",
"meta": map[string]any{"token": "jwt_xyz"},
}
masked := sensitive.RedactAny(data)
// β map[user:alice password:[REDACTED] meta:map[token:[REDACTED]]]
}| Preset | Strategy | Use Case |
|---|---|---|
PresetStrict |
Full redaction for secrets, partial for PII | Production logs, external APIs |
PresetAudit |
Hash tokens, mask secrets, partial PII | Debugging, compliance audits |
PresetDebug |
Hash secrets, expose non-critical fields | Local development, staging |
// Apply preset (validates automatically)
if err := sensitive.ApplyPreset(sensitive.PresetAudit); err != nil {
log.Fatalf("invalid preset: %v", err)
}_ = sensitive.SetFieldConfig("customer_phone", sensitive.FieldConfig{
Strategy: sensitive.StrategyPartialMask,
Options: sensitive.MaskOptions{
VisiblePrefix: 3,
VisibleSuffix: 2,
MaskChar: 'β’',
MinLength: 10,
},
})
fmt.Println(sensitive.MaskValue("customer_phone", "+79991234567"))
// β +79β’β’β’β’β’β’β’67cfg := sensitive.Config{
DefaultStrategy: sensitive.StrategyPartialMask,
MaxDepth: 10,
Enabled: true,
}
if err := cfg.Validate(); err != nil {
// Handle invalid config (e.g., negative VisiblePrefix)
}
_ = sensitive.UpdateConfig(cfg) // Atomic, validated updateRedactAny walks any Go type, masking sensitive keys at any depth. Depth is limited by Config.MaxDepth to prevent abuse.
payload := []any{
map[string]any{"email": "user@test.com"},
map[string]any{"api_key": "sk_live_xxx"},
}
safe := sensitive.RedactAny(payload)Drop-in replacement for json.Marshal that applies masking before encoding.
logEntry := map[string]any{"email": "a@b.com", "token": "abc"}
jsonBytes, _ := sensitive.Marshal(logEntry) // token & email maskedWrap sensitive fields in your structs for automatic masking during marshaling.
type LoginRequest struct {
Username string `json:"username"`
Password sensitive.SensitiveValue `json:"password"`
}
req := LoginRequest{
Username: "alice",
Password: sensitive.NewSensitive("password", "MyP@ss!"),
}
json.Marshal(req) // β {"username":"alice","password":"[REDACTED]"}// Raw query
sensitive.RedactRawQuery("user=alice&password=123&redirect=/home")
// β user=alice&password=[REDACTED]&redirect=/home
// url.Values
values := url.Values{"email": {"a@b.com"}, "csrf_token": {"tok"}}
safe := sensitive.RedactValues(values)- π This package does not encrypt data. It only masks values for output/logging.
- π« Never use
PresetDebugin production or public-facing environments. - π Apply masking at the boundary (before writing to logs, sending HTTP responses, or storing in tracing systems), not inside business logic.
- π
SensitiveValue.UnmarshalJSONreturns the original value. Use it only for outgoing data. - π‘οΈ For data at rest or in transit, always use proper cryptographic libraries (e.g.,
crypto/aes,crypto/tls).
# Run all tests + examples
go test ./... -v
# Run only example tests (validates output)
go test ./... -run=Example -v
# Benchmarks (performance profiling)
go test ./... -bench=. -benchmem -benchtime=5s
# Coverage report
go test ./... -coverprofile=coverage.out
go tool cover -html=coverage.out| Function | Description |
|---|---|
IsSensitive(name string) bool |
Check if a field name is marked as sensitive |
MaskValue(key, value string) string |
Apply configured strategy to a value |
RedactAny(v any) any |
Recursively mask maps, slices, and nested structures |
Marshal(v any) ([]byte, error) |
JSON marshal with automatic masking |
ApplyPreset(PresetType) error |
Atomically apply & validate a preset configuration |
SetFieldConfig(string, FieldConfig) error |
Override strategy/options for a specific field |
NewSensitive(field, value string) SensitiveValue |
Create JSON-marshalable sensitive wrapper |
RedactRawQuery(string) string |
Mask sensitive parameters in URL query strings |
Enable(bool) / Reset() |
Toggle globally or reset to defaults (useful in tests) |
Full documentation: pkg.go.dev/github.com/sudoki2015/sensitive
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing) - Run tests & benchmarks (
go test ./... -v) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing) - Open a Pull Request
MIT License. See LICENSE for details.
Built for developers who care about data privacy without sacrificing DX. π