regexutil

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: May 13, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package regexutil provides bounded, DoS-safe wrappers around regexp.Compile for every call path that takes a user- or config-supplied regex pattern.

Threat model

Go's regexp engine is RE2-based and therefore does not suffer classical catastrophic backtracking at match time. Compilation, however, is not guaranteed linear: a pathological pattern (e.g. `(a+)+b`, deeply nested alternation, or simply very long repetition chains) can take measurable wall-clock time inside regexp.Compile and allocate an automaton of many thousands of states. That is sufficient to hang a CLI's update flow or freeze an interactive TUI.

This package applies two defences uniformly:

  1. A byte-length cap (MaxPatternLength) rejects oversize patterns before any compile work begins.
  2. A wall-clock timeout on the compile itself (DefaultCompileTimeout) bounds the worst case for anything that slips past the length cap.

Call-site discipline: any regex compiled from a pattern that originates outside the binary (config file, CLI flag, TUI input, HTTP payload, message queue) MUST go through CompileBounded or CompileBoundedTimeout. Literal patterns known at build time can — and should — continue to use regexp.MustCompile directly.

Goroutine leak tradeoff

regexp.Compile is not context-aware, so the timeout path launches the compile in a goroutine and returns on timeout while that goroutine keeps running until the compile finishes (or forever, for truly pathological inputs). This is a bounded leak: the number of distinct pathological patterns a single process ever sees is small; the goroutine holds a single compile's working set; the caller gets their error immediately and can continue. If a future Go version exposes a context-aware compile, migrate.

Logging

Rejection errors never include the offending pattern — only its length and the rejection kind. Logging the pattern would let an attacker fill logs with content of their choosing. Callers that wish to surface the pattern to the operator should do so from a trusted-source context where log amplification is not a concern.

Index

Constants

View Source
const DefaultCompileTimeout = 100 * time.Millisecond

DefaultCompileTimeout is the wall-clock timeout applied to a single regexp.Compile call. Compiling a well-behaved 1 KiB pattern takes well under 1 ms on typical hardware; 100 ms is two orders of magnitude above normal and still imperceptible for interactive use.

View Source
const MaxPatternLength = 1024

MaxPatternLength is the maximum accepted pattern length, in bytes. Patterns longer than this are rejected without being compiled. Legitimate filename patterns and search queries are short; 1 KiB is generous for the former and ample for the latter.

Variables

View Source
var ErrPatternCompileTimeout = errors.New("regex pattern compile timed out")

ErrPatternCompileTimeout is returned when regexp.Compile does not finish within the configured timeout — typically a sign of a pathological pattern.

View Source
var ErrPatternInvalid = errors.New("regex pattern is invalid")

ErrPatternInvalid is returned when regexp.Compile fails for a reason other than length or timeout (i.e. syntax errors).

View Source
var ErrPatternTooLong = errors.New("regex pattern exceeds maximum length")

ErrPatternTooLong is returned when a pattern exceeds MaxPatternLength. Distinguish with errors.Is.

Functions

func CompileBounded

func CompileBounded(ctx context.Context, pattern string) (*regexp.Regexp, error)

CompileBounded compiles pattern with a byte-length cap of MaxPatternLength and a wall-clock timeout of whichever of DefaultCompileTimeout or the deadline already present on ctx expires first.

The returned error wraps one of ErrPatternTooLong, ErrPatternCompileTimeout, or ErrPatternInvalid so callers can distinguish the failure mode via errors.Is.

Use this wherever a pattern originates outside the binary: config file, CLI flag, HTTP payload, TUI input. Literal patterns known at build time should keep using regexp.MustCompile.

func CompileBoundedTimeout

func CompileBoundedTimeout(pattern string, timeout time.Duration) (*regexp.Regexp, error)

CompileBoundedTimeout is a convenience wrapper that applies a caller-supplied timeout via context.WithTimeout on top of context.Background. Use this from call sites that do not naturally carry a context.Context (e.g. a Bubble Tea TUI loop).

The effective timeout is the minimum of timeout and DefaultCompileTimeout, so you cannot accidentally widen the package's wall-clock bound.

Types

This section is empty.

Jump to

Keyboard shortcuts

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