recheck
Version:
The trustworthy ReDoS checker
401 lines (355 loc) • 8.94 kB
TypeScript
/**
* Checks whether the given RegExp pattern is ReDoS vulnerable or safe.
* It takes an optional argument to specify parameters.
*/
export function check(
source: string,
flags: string,
params?: Parameters & HasAbortSignal,
): Promise<Diagnostics>;
/**
* Synchronous version of `check`. Take care that it will block the Node.js process.
*/
export function checkSync(
source: string,
flags: string,
params?: Parameters,
): Diagnostics;
/**
* Parameters is parameters for analysis.
*/
export type Parameters = {
/**
* The type of acceleration mode strategy on fuzzing.
*
* There are three acceleration mode strategies.
*
* - `auto` uses acceleration mode as default. However, if the regular expression has backreferences, it turns off the acceleration mode.
* - `on` turns on the acceleration mode.
* - `off` turns off the acceleration mode.
*
* (default: `'auto'`)
*/
accelerationMode?: "auto" | "on" | "off";
/**
* The upper limit on the number of characters read by VM on the attack.
*
* (default: `1500000000`)
*/
attackLimit?: number;
/**
* The upper limit of matching time on the attack.
*
* (default: `1000`)
*/
attackTimeout?: number | null;
/**
* The type of checker to be used.
*
* There are three checker types.
*
* - `auto` checker uses the criteria to decide which algorithm is better to use against a regular expression, the algorithm based on automata theory or the fuzzing algorithm.
* - `fuzz` checker uses the fuzzing algorithm with static analysis.
* - `automaton` checker uses the algorithm based on automata theory.
*
* (default: `'auto'`)
*/
checker?: "auto" | "fuzz" | "automaton";
/**
* The number of crossover on each generation.
*
* (default: `25`)
*/
crossoverSize?: number;
/**
* The ratio of the number of characters read to the maximum number to be considered as a hot spot.
*
* (default: `0.001`)
*/
heatRatio?: number;
/**
* The upper limit on the number of characters read by VM on incubation.
*
* (default: `25000`)
*/
incubationLimit?: number;
/**
* The upper limit of matching time on incubation.
*
* (default: `250`)
*/
incubationTimeout?: number | null;
/**
* The logger function to record execution traces.
*
* To disable the logging, `null` in TypeScript or `None` in Scala should be passed.
*
* (default: `null`)
*/
logger?: (message: string) => void;
/**
* The maximum length of the attack string on fuzzing.
*
* (default: `300000`)
*/
maxAttackStringSize?: number;
/**
* The maximum degree to be considered in fuzzing.
*
* (default: `4`)
*/
maxDegree?: number;
/**
* The maximum length of the gene string on fuzzing.
*
* (default: `2400`)
*/
maxGeneStringSize?: number;
/**
* The maximum size of each generation on fuzzing.
*
* (default: `100`)
*/
maxGenerationSize?: number;
/**
* The maximum size of the initial generation on fuzzing.
*
* (default: `500`)
*/
maxInitialGenerationSize?: number;
/**
* The maximum number of fuzzing iteration.
*
* (default: `10`)
*/
maxIteration?: number;
/**
* The maximum size of NFA to determine which algorithm is used.
*
* (default: `35000`)
*/
maxNFASize?: number;
/**
* The maximum size of the regular expression pattern to determine which algorithm is used.
*
* (default: `1500`)
*/
maxPatternSize?: number;
/**
* The maximum length of the attack string on recall validation.
*
* (default: `300000`)
*/
maxRecallStringSize?: number;
/**
* The maximum number of sum of repetition quantifier’s repeat counts to determine which algorithm is used.
*
* (default: `30`)
*/
maxRepeatCount?: number;
/**
* The maximum number of each repetition quantifier’s repeat count on `static` seeding.
*
* (default: `30`)
*/
maxSimpleRepeatCount?: number;
/**
* The number of mutation on each generation.
*
* (default: `50`)
*/
mutationSize?: number;
/**
* The PRNG seed number.
*
* (default: `0`)
*/
randomSeed?: number;
/**
* The upper limit on the number of characters read by VM on the recall validation.
*
* (default: `1500000000`)
*/
recallLimit?: number;
/**
* The upper limit of matching time on the recall validation.
*
* If this value is negative, then the recall validation is skipped.
*
* (default: `-1000`)
*/
recallTimeout?: number | null;
/**
* The type of seeder to be used in fuzzing.
*
* There are two seeders.
*
* - `static` seeder uses the seeding algorithm based on the automata theory.
* - `dynamic` seeder uses the seeding algorithm with dynamic analysis.
*
* (default: `'static'`)
*/
seeder?: "static" | "dynamic";
/**
* The upper limit on the number of characters read by VM on `dynamic` seeding.
*
* (default: `1000`)
*/
seedingLimit?: number;
/**
* The upper limit of matching time on `dynamic` seeding.
*
* (default: `100`)
*/
seedingTimeout?: number | null;
/**
* The upper limit of checking time.
*
* If the checking time exceeds this limit, the result will be reported as `timeout`. If the value is positive infinite in Scala or `null` in TypeScript, the result never becomes `timeout`.
*
* The `timeout` time begins to be measured as soon as the check starts. Note that the `timeout` does not occur while the input is in the queue waiting to be checked.
*
* In TypeScript, a number value is treated as in milliseconds.
*
* (default: `10000`)
*/
timeout?: number | null;
};
/**
* HasAbortSignal is a mix-in type for having `signal` field.
*/
export type HasAbortSignal = {
/**
* Signal to abort the check.
*/
signal?: AbortSignal;
};
/**
* Diagnostics is an analyzing result.
* It takes one of the following three statuses:
*
* - `safe`: The given RegExp is safe.
* - `vulnerable`: The given RegExp is potentially vulnerable.
* - `unknown`: An error is occurred on analyzing.
* As a result, it is unknown whether the RegExp is safe or vulnerable.
*/
export type Diagnostics =
| SafeDiagnostics
| VulnerableDiagnostics
| UnknownDiagnostics;
/**
* SafeDiagnostics is a diagnostics against a safe RegExp.
*/
export type SafeDiagnostics = {
source: string;
flags: string;
status: "safe";
checker: "automaton" | "fuzz";
complexity: SafeComplexity;
};
/**
* VulnerableDiagnostics is a diagnostics against a vulnerable RegExp.
*/
export type VulnerableDiagnostics = {
source: string;
flags: string;
status: "vulnerable";
checker: "automaton" | "fuzz";
attack: AttackPattern;
complexity: VulnerableComplexity;
hotspot: Hotspot[];
};
/**
* UnknownDiagnostics is a diagnostics when an error is occurred on analyzing.
*/
export type UnknownDiagnostics = {
source: string;
flags: string;
status: "unknown";
checker?: "automaton" | "fuzz";
error: Error;
};
/**
* SafeComplexity is a safe complexity.
*/
export type SafeComplexity = {
type: "constant" | "linear" | "safe";
summary: string;
isFuzz: boolean;
};
/**
* VulnerableComplexity is a vulnerable complexity.
*/
export type VulnerableComplexity = PolynomialComplexity | ExponentialComplexity;
/**
* PolynomialComplexity is a polynomial (super-linear) complexity.
* This complexity is vulnerable typically.
*/
export type PolynomialComplexity = {
type: "polynomial";
summary: string;
degree: number;
isFuzz: boolean;
};
/**
* ExponentialComplexity is an exponential complexity.
* This complexity is vulnerable very.
*/
export type ExponentialComplexity = {
type: "exponential";
summary: string;
isFuzz: boolean;
};
/**
* Hotspot is a hotspot of the RegExp pattern.
*/
export type Hotspot = {
start: number;
end: number;
temperature: "heat" | "normal";
};
/**
* Error is a possible error on analyzing.
*/
export type Error = Timeout | Cancel | Unsupported | Invalid | Unexpected;
/**
* Timeout is a timeout error.
*/
export type Timeout = { kind: "timeout" };
/** Cancel is a cancel error. */
export type Cancel = { kind: "cancel" };
/**
* Unsupported is an error reported when the RegExp is not supported.
*/
export type Unsupported = {
kind: "unsupported";
message: string;
};
/**
* Invalid is an error reported when the RegExp is invalid.
*/
export type Invalid = {
kind: "invalid";
message: string;
};
/**
* Unexpected is an error reported when unexpected error occurs.
*/
export type Unexpected = {
kind: "unexpected";
message: string;
};
/**
* AttackPattern is an attack pattern string.
*/
export type AttackPattern = {
pumps: {
prefix: string;
pump: string;
bias: number;
}[];
suffix: string;
base: number;
string: string;
pattern: string;
};