Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/enclave/core-libraries/ast-guard/pre-scanner.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,10 @@ The pre-scanner detects dangerous regex patterns that cause exponential backtrac

### Manual ReDoS Analysis

`@enclave-vm/ast/redos` exports the analyzer on its own: it loads none of the parser (`acorn`, `acorn-walk`, `astring`) that the package root loads. The package root exports the same functions.

```ts
import { analyzeForReDoS } from '@enclave-vm/ast';
import { analyzeForReDoS } from '@enclave-vm/ast/redos';

// Analyze a pattern for ReDoS vulnerabilities
const result = analyzeForReDoS('(a+)+', 'catastrophic');
Expand Down
3 changes: 2 additions & 1 deletion docs/enclave/libraries/ast-guard.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ The pre-scanner supports three regex handling modes:
- **`allow`** - Allow all regex without analysis (Permissive only)

```ts
import { createPreScannerConfig, analyzeForReDoS } from '@enclave-vm/ast';
// The analyzer alone, without the parser the package root loads
import { analyzeForReDoS } from '@enclave-vm/ast/redos';

// Analyze a pattern for ReDoS vulnerabilities
const result = analyzeForReDoS('(a+)+', 'catastrophic');
Expand Down
13 changes: 13 additions & 0 deletions libs/ast/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,19 @@ npm run test:coverage
- **Validation time**: ~1-10ms per rule (depends on complexity)
- **Memory**: Minimal overhead, AST is shared across rules

## ReDoS Analysis Without the Parser

To check regular expressions for catastrophic backtracking without validating JavaScript, import the analyzer from `@enclave-vm/ast/redos`. It loads none of the parser (`acorn`, `acorn-walk`, `astring`) that the package root loads: about 8 KB instead of 240 KB plus the parser.

```ts
import { analyzeForReDoS, REDOS_THRESHOLDS } from '@enclave-vm/ast/redos';

const { score } = analyzeForReDoS('(a+)+$', 'catastrophic');
if (score >= REDOS_THRESHOLDS.BLOCK) throw new Error('Pattern can backtrack catastrophically');
```

It also exports `REDOS_PATTERNS`, `calculateStarHeight` and the `ReDoSAnalysisResult` type, the same as the package root.

## Comparison

| Feature | AST Guard | ESLint | TypeScript |
Expand Down
7 changes: 7 additions & 0 deletions libs/ast/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@
"import": "./dist/esm/index.mjs",
"require": "./dist/index.js",
"default": "./dist/index.js"
},
"./redos": {
"development": "./src/redos.ts",
"types": "./dist/redos.d.ts",
"import": "./dist/esm/redos.mjs",
"require": "./dist/redos.js",
"default": "./dist/redos.js"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
}
},
"dependencies": {
Expand Down
2 changes: 2 additions & 0 deletions libs/ast/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"bundle": true,
"thirdParty": false,
"platform": "node",
"additionalEntryPoints": ["libs/ast/src/redos.ts"],
"assets": ["libs/ast/README.md", "libs/ast/CHANGELOG.md", "LICENSE", "libs/ast/package.json"],
"esbuildOptions": {
"outExtension": { ".js": ".js" },
Expand All @@ -39,6 +40,7 @@
"bundle": true,
"thirdParty": false,
"platform": "node",
"additionalEntryPoints": ["libs/ast/src/redos.ts"],
"esbuildOptions": {
"outExtension": { ".js": ".mjs" },
"external": ["acorn", "acorn-walk", "astring", "@types/estree"]
Expand Down
21 changes: 21 additions & 0 deletions libs/ast/src/__tests__/redos-entry.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
jest.mock('acorn', () => {
throw new Error('@enclave-vm/ast/redos loaded acorn');
});
jest.mock('acorn-walk', () => {
throw new Error('@enclave-vm/ast/redos loaded acorn-walk');
});
jest.mock('astring', () => {
throw new Error('@enclave-vm/ast/redos loaded astring');
});

import { REDOS_THRESHOLDS, analyzeForReDoS, calculateStarHeight } from '../redos';

describe('@enclave-vm/ast/redos', () => {
it('analyzes patterns without loading the parser', () => {
const nested = analyzeForReDoS('(a+)+', 'catastrophic');
expect(nested.vulnerable).toBe(true);
expect(nested.score).toBeGreaterThanOrEqual(REDOS_THRESHOLDS.BLOCK);
expect(analyzeForReDoS('[a-z]+', 'polynomial').vulnerable).toBe(false);
expect(calculateStarHeight('(a*)*')).toBe(2);
});
});
11 changes: 11 additions & 0 deletions libs/ast/src/redos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* `@enclave-vm/ast/redos`: the ReDoS analyzer on its own, for code that checks regular expressions without validating
* JavaScript. It loads none of the parser (acorn, acorn-walk, astring) that the package root loads.
*/
export {
REDOS_PATTERNS,
REDOS_THRESHOLDS,
analyzeForReDoS,
calculateStarHeight,
} from './pre-scanner/checks/regex-check';
export type { ReDoSAnalysisResult } from './pre-scanner/checks/regex-check';
Loading