redact

package module
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 24, 2026 License: MIT Imports: 2 Imported by: 0

README

redact

Strip credential-like content from free-form strings before they reach logs, telemetry, or any third-party surface

Go Reference Pipeline Coverage phpboyscout Go toolkit

Part of the phpboyscout Go toolkit — small, framework-free Go modules extracted from go-tool-base. Docs: redact.go.phpboyscout.uk


gitlab.com/phpboyscout/go/redact redacts credential-like content from free-form strings at the boundary between trusted and untrusted observability surfaces — telemetry vendors, log aggregators, metric stores. Error messages, command arguments, and HTTP header values routinely carry secrets by accident (a URL with embedded userinfo, an --api-key=sk-… flag in os.Args, an Authorization header quoted in an export error). Route those through redact.String on the way out and they never leave the process in the clear.

Design

  • Zero dependencies. Pure standard library (regexp, strings) — nothing but the module enters your graph. A depfootprint_test.go guard enforces it.
  • Boundary redaction. Sanitise where data leaves the host, not everywhere.
  • Conservative by default. The opaque-token fallback requires ≥41 chars so it never false-positives on UUIDs, MD5, or SHA-1.

Install

go get gitlab.com/phpboyscout/go/redact

Usage

import "gitlab.com/phpboyscout/go/redact"

safe := redact.String("failed calling https://user:s3cr3t@api.example.com?api_key=sk-abc123…")
// → credentials in the URL userinfo, the api_key query param, and the sk- token are masked

msg := redact.Error(err) // redact.String applied to err.Error() (nil-safe)

if redact.IsSensitiveHeaderKey("Authorization") { /* … redact this header's value … */ }

redact.String strips URL userinfo for any scheme (https://, postgres://, redis://, …), credential name=value assignments, JSON credential fields such as "access_token" and "client_secret", Authorization-header tokens, JWTs, well-known provider prefixes (sk-, ghp_, glpat-, AIza, AKIA, Slack), and long opaque tokens. SensitiveHeaderKeys / IsSensitiveHeaderKey identify headers whose values should be redacted.

Limitations

Pattern catalogues never reach 100% recall, and this one is deliberately conservative:

  • No configuration. You cannot add, disable or reorder a pattern — the package exports four symbols and nothing to tune. Compose around it instead.
  • String does not mask arbitrary header values. It knows Authorization: and nothing else; X-API-Key: … passes through. That is what the header symbols are for.
  • Bespoke and short secrets slip through. The catch-all fallback needs 41 characters, and each provider prefix has a hard minimum length.
  • Patterns are ASCII-only, and redaction is one-way — nothing to reverse and no record of what was replaced.

What redact does not do states the full boundary.

Documentation

Full guides, reference and threat model: redact.go.phpboyscout.uk. Generated API docs and runnable examples: pkg.go.dev.

License

See LICENSE.

Documentation

Overview

Package redact strips credential-like content from free-form strings at the boundary between trusted and untrusted observability surfaces (telemetry vendors, log aggregators, metric stores).

Threat model

Error messages, command arguments, and HTTP header values routinely carry credentials by accident: an HTTP client wraps a URL with an embedded token, a command-line flag like `--api-key=sk-abc123` lands in `os.Args`, an error from a failed OTLP export quotes an Authorization header. The moment that content reaches a third-party ingest, it is outside the operator's control — potentially replicated, indexed, and retained longer than intended.

The right defence is to redact at the boundary. This package applies pattern-based redaction in-process, before data is shipped. Callers do not need to remember to sanitise: the collector, middleware, and logger helpers route untrusted strings through String on their way out.

Discipline

Use String or Error anywhere a caller-supplied or environment-derived string is written to telemetry, distributed logs, or any surface where credentials would be harmful. Do not use it on local process logs that never leave the host — those may need raw content for debugging.

Limitations

Pattern catalogues never reach 100 % recall. The rules here catch the common shapes (URL userinfo for any RFC 3986 scheme — https as well as connection strings like postgres://, redis://, amqp://, mongodb+srv:// — common query-parameter names, JSON-form credential keys such as "access_token" or "client_secret", Authorization-header tokens, well-known provider prefixes like "sk-", "ghp_", "AIza", "AKIA", and a conservative ≥ 41-char opaque token fallback). A custom credential in a non-standard format will slip through; callers handling such inputs must supply their own redaction upstream.

The fallback opaque-token pattern is intentionally conservative (≥ 41 chars) so it does not false-positive on UUIDs (36 with hyphens), MD5 (32) or SHA-1 (40) hashes. SHA-256 (64 chars) will match — accepted tradeoff; hashes rarely appear in error strings.

Patterns are ASCII-only. Virtually all real-world provider tokens are ASCII; UTF-8 credentials in the wild are vanishingly rare.

See https://redact.go.phpboyscout.uk for the full threat model and design rationale.

Index

Constants

This section is empty.

Variables

View Source
var SensitiveHeaderKeys = []string{
	"Authorization",
	"Proxy-Authorization",
	"Cookie",
	"Set-Cookie",
	"X-API-Key",
	"X-API-Token",
	"X-Auth-Token",
	"X-Access-Token",
	"X-CSRF-Token",
	"X-Session-Token",
}

SensitiveHeaderKeys is the default set of HTTP header names whose values should be redacted whenever headers are written to a log, telemetry, or error surface. Match is case-insensitive.

Callers that need to add more entries should compose a wider set locally rather than mutating this slice at runtime.

Functions

func Error

func Error(err error) string

Error is a convenience wrapper equivalent to String(err.Error()). Returns "" for a nil error so callers do not need to guard.

func IsSensitiveHeaderKey

func IsSensitiveHeaderKey(name string) bool

IsSensitiveHeaderKey reports whether name identifies a header whose value should be redacted before logging. Matches either (a) an entry of SensitiveHeaderKeys (case-insensitive exact) or (b) the fuzzy substring pattern used for advisory warnings.

Use (a) when deciding what to redact; use the result of this function when deciding whether to WARN about a caller-supplied header name.

func String

func String(s string) string

String applies all redaction patterns to s and returns the sanitised result. Safe to call on any string; idempotent; returns the input unchanged when no sensitive patterns match.

Invariants guaranteed by [FuzzRedactString]:

  • No panic on any input.
  • len(String(s)) <= len(s) + K, where K is a small constant accounting for the fixed-length replacements (e.g. "***", "<redacted-token>"). Never pathologically grows the input.
  • String(String(s)) == String(s) — applying redaction twice produces the same output as applying it once.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL