RegexSafetyManager
Safety wrapper for user-supplied regex compilation and matching.
ReDoS is mitigated by two complementary defences:
- A cheap pre-screen (safeCompile) rejects null/empty/oversized patterns and a set of well-known catastrophic-backtracking shapes before they are ever compiled.
- A hard execution bound (safeFind/safeMatches) caps the number of character accesses the backtracking engine may perform for a single match. Catastrophic backtracking explores an exponential number of paths, each of which reads characters, so a step ceiling deterministically bounds worst-case runtime - even for dangerous patterns the pre-screen misses - without relying on thread interruption or wall-clock timeouts.
The step bound is the real security boundary: any pattern that reaches the matching helpers is safe regardless of how it was constructed. The shape blocklist is only a fast early-reject and must not be relied on for safety.
NOTE: kept intentionally in sync with org.llm4s.runner.WorkspaceRegexSafetyManager, which duplicates this logic because the workspace runner module cannot depend on core. Changes to the heuristics or bounds here should be mirrored there.
Attributes
- Graph
-
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
RegexSafetyManager.type
Members list
Type members
Classlikes
Raised when a match exceeds its step budget (likely catastrophic backtracking).
Raised when a match exceeds its step budget (likely catastrophic backtracking).
Attributes
- Supertypes
-
class RuntimeExceptionclass Exceptionclass Throwabletrait Serializableclass Objecttrait Matchableclass AnyShow all
Value members
Concrete methods
Compiles text as a literal pattern: it is quoted with Pattern.quote, so regex metacharacters in it match themselves.
Compiles text as a literal pattern: it is quoted with Pattern.quote, so regex metacharacters in it match themselves.
It returns the Pattern directly and does not apply the checks of safeCompile. A quoted pattern has no quantifiers or alternation, so the shapes those checks look for cannot occur in it.
Value parameters
- flags
-
java.util.regex.Patternflags; 0 by default - pattern
-
the text to match literally
Attributes
- Returns
-
a
Patternthat matchespatternas plain text
Compiles text as a literal pattern that ignores case (Pattern.CASE_INSENSITIVE).
Compiles text as a literal pattern that ignores case (Pattern.CASE_INSENSITIVE).
Like compileLiteral, it quotes the text and does not apply the checks of safeCompile.
Value parameters
- pattern
-
the text to match literally
Attributes
- Returns
-
a case-insensitive
Patternthat matchespatternas plain text
Replaces every occurrence of a literal text in the input.
Replaces every occurrence of a literal text in the input.
Both literalPattern and replacement are taken literally: the pattern is compiled with compileLiteral and the replacement goes through Matcher.quoteReplacement, so $ and \ in it have no special meaning.
Value parameters
- caseInsensitive
-
whether
literalPatternmatches regardless of case (Pattern.CASE_INSENSITIVE) - input
-
the text to search
- literalPattern
-
the text to find, matched literally
- replacement
-
the text to put in its place, inserted literally
Attributes
- Returns
-
the input with every occurrence replaced
Replaces the first occurrence of a literal text in the input.
Replaces the first occurrence of a literal text in the input.
It is replaceAllLiteral for the first occurrence only: literalPattern and replacement are both taken literally, the replacement through Matcher.quoteReplacement.
Value parameters
- caseInsensitive
-
whether
literalPatternmatches regardless of case (Pattern.CASE_INSENSITIVE) - input
-
the text to search
- literalPattern
-
the text to find, matched literally
- replacement
-
the text to put in its place, inserted literally
Attributes
- Returns
-
the input with its first occurrence replaced, or the input unchanged if there is none
Compiles a user-supplied pattern after the pre-screen, without throwing.
Compiles a user-supplied pattern after the pre-screen, without throwing.
Returns Left with a message when the pattern is null, empty or blank, is longer than 1000 characters, matches one of the known catastrophic-backtracking shapes (nested quantifiers, or a quantified alternation whose alternatives overlap), or is not valid regex syntax. The pre-screen is only an early reject: bound matching with safeFind or safeMatches.
Value parameters
- flags
-
java.util.regex.Patternflags, such asPattern.CASE_INSENSITIVE; 0 by default - pattern
-
the regular expression to compile
Attributes
- Returns
-
the compiled
Pattern, orLeftwith the reason it was rejected
Tells whether the pattern is found anywhere in the input (Matcher.find), within a step budget.
Tells whether the pattern is found anywhere in the input (Matcher.find), within a step budget.
Returns Left with a message when the input is null or longer than 100000 characters, when matching reads more than maxSteps characters (likely catastrophic backtracking), when the pattern recurses too deeply for the input, or when matching fails for another non-fatal reason. See safeMatches for whole-input matching.
Value parameters
- input
-
the text to search
- maxSteps
-
the most character accesses one match may make; 10000000 by default
- pattern
-
the compiled pattern, e.g. from safeCompile
Attributes
- Returns
-
Right(true)if a match is found,Right(false)if not, orLeftwith the reason matching stopped
Tells whether the pattern matches the whole input (Matcher.matches), within a step budget.
Tells whether the pattern matches the whole input (Matcher.matches), within a step budget.
It is safeFind for the whole input: find succeeds on a match anywhere in the input, matches only when the pattern matches all of it. The same Left cases apply: a null or over-long input (more than 100000 characters), an exceeded step budget, too deep a recursion, or another non-fatal failure.
Value parameters
- input
-
the text to match
- maxSteps
-
the most character accesses one match may make; 10000000 by default
- pattern
-
the compiled pattern, e.g. from safeCompile
Attributes
- Returns
-
Right(true)if the whole input matches,Right(false)if not, orLeftwith the reason matching stopped