Skip to content

Conversation

@frontegg-david
Copy link
Contributor

@frontegg-david frontegg-david commented Jan 6, 2026

Summary by CodeRabbit

  • New Features

    • Resource-exhaustion protections for CPU/memory (BigInt exponent limits, large arrays, excessive string ops) and an option to disable AST validation.
  • Security Enhancements

    • Stronger sandbox hardening (disable dynamic code generation, safer Object surface, prototype freezing), pre-validation before transforms, and enforced memory limits for large joins/concats.
  • Tests

    • Expanded suites to accept either AST-level blocking or runtime sandbox blocking as valid outcomes.
  • Documentation

    • Added docs describing the resource-exhaustion rule and configuration.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 6, 2026

📝 Walkthrough

Walkthrough

A ResourceExhaustionRule was added to ast-guard and enabled in the AgentScript preset. Enclave VM sandboxing and memory/CPU protections were hardened (SafeObject, prototype freezes, codeGeneration disabled, memory-join enforcement). AST validation now runs before memory/sidecar transforms. Tests and docs were updated for dual AST+runtime defenses.

Changes

Cohort / File(s) Change summary
AST rule & preset
libs/ast-guard/src/rules/resource-exhaustion.rule.ts, libs/ast-guard/src/rules/index.ts, libs/ast-guard/src/presets/agentscript.preset.ts
Add ResourceExhaustionRule and ResourceExhaustionOptions, export the rule, and instantiate it in the AgentScript preset with configured thresholds (BigInt exponent, array size, string.repeat, constructor access, exponentiation blocking flag).
Enclave validation & transforms
libs/enclave-vm/src/enclave.ts
Move AST validation to run before memory/sidecar transforms; apply sidecar/memory-tracking transforms only when validation passes.
VM context & sandbox hardening
libs/enclave-vm/src/adapters/vm-adapter.ts, libs/enclave-vm/src/adapters/worker-pool/worker-script.ts, libs/enclave-vm/src/double-vm/... (e.g., double-vm-wrapper.ts, parent-vm-bootstrap.ts)
Inject SafeObject, expand forbidden globals, disable codeGeneration { strings:false, wasm:false } in vm.createContext, freeze prototypes, expose memoryLimit to host config, and apply prototype patches for memory protections.
Memory tracking & enforcement
libs/enclave-vm/src/memory-proxy.ts
Add pre-join size estimation, tracked join/toString, throw MemoryLimitError when join exceeds memoryLimit, wrap array instances and static constructors (from, of) to return tracked arrays.
Double VM runtime changes
libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts, libs/enclave-vm/src/double-vm/double-vm-wrapper.ts
Create parent/inner VMs with codeGeneration restrictions; inject memory-protection prototype patches; use SafeObject and freeze prototypes; surface memoryLimit to inner VM.
Tests — acceptance & unit
libs/enclave-vm/src/__tests__/* (e.g., resource-exhaustion.spec.ts, literal-constructor-escape.spec.ts, function-gadget-attacks.spec.ts, runtime-attack-vectors.spec.ts, others)
Add extensive resource-exhaustion tests; introduce helpers (expectSecureOutcome, expectSecureResult) and validate option usage; broaden test expectations to accept either AST "AgentScript validation failed" or runtime "Security violation" outcomes.
Docs
docs/draft/docs/libraries/ast-guard.mdx, docs/live/docs/libraries/ast-guard.mdx
Document ResourceExhaustionRule: detected patterns, configuration options, example usage and blocked attack examples.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant Enclave
participant ASTValidator as "AST Validator\n(ast-guard)"
participant Transformer as "Transforms\n(memory/sidecar)"
participant WorkerPool
participant VM as "VM / Double VM"
participant Runtime as "Sandbox Runtime\n/ Memory Proxy"

Client->>Enclave: submit(code, options)
Enclave->>ASTValidator: validate(code)
alt AST validation fails
    ASTValidator-->>Enclave: AgentScript validation failed
    Enclave-->>Client: return validation error
else AST validation passes
    ASTValidator-->>Enclave: valid
    Enclave->>Transformer: apply memory/sidecar transforms
    Transformer-->>Enclave: transformed code
    Enclave->>WorkerPool: schedule execution
    WorkerPool->>VM: createContext(codeGeneration:{strings:false,wasm:false}, safeGlobals)
    VM->>Runtime: inject SafeObject, freeze prototypes, wire memoryLimit
    VM->>Runtime: execute(transformed code)
    alt runtime enforces block
        Runtime-->>Client: "Security violation" / MemoryLimitError
    else execution succeeds
        Runtime-->>Client: result
    end
end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

"I hopped through code with careful paws,
I chased the loops and counted flaws. 🐇
I planted rules in AST and VM,
I wrapped SafeObject like a gem,
Now scripts stay tame — hooray applause!"

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of the PR, which is to add CPU and memory exhaustion protection through the new ResourceExhaustionRule and related security enhancements across the codebase.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a298952 and 4396a81.

📒 Files selected for processing (1)
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
🧰 Additional context used
📓 Path-based instructions (1)
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
🧬 Code graph analysis (1)
libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (1)
libs/enclave-vm/src/types.ts (1)
  • SecurityLevel (24-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Performance
  • GitHub Check: Test
🔇 Additional comments (8)
libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (8)

58-66: Good documentation of defense-in-depth rationale.

The comments clearly explain why removing Function is still valuable even with codeGeneration.strings=false — it eliminates potential future bypass vectors. The ATK-RECON-01 reference provides useful context for security audits.


68-135: Well-structured security levels with clear categorization.

The hierarchical dangerous globals configuration with inline comments improves maintainability and security auditing. Good that ShadowRealm is blocked at all levels given its realm creation capabilities.


776-780: Good security hardening with code generation disabled.

Setting codeGeneration: { strings: false, wasm: false } at context creation correctly prevents sandbox escape via new Function() from strings and WebAssembly instantiation. This is the correct placement (createContext, not runInContext).


782-847: Previous ordering issue resolved: memory patching now correctly precedes sanitization.

The memory-safe prototype patching now correctly executes before ${sanitizeContextCode} (line 850), addressing the previous review concern. The approach of using Object.getPrototypeOf("") and Object.getPrototypeOf([]) correctly captures the inner VM's intrinsic prototypes rather than the parent realm's.


852-895: Previous critical issue resolved: inner VM prototypes now properly frozen.

The dual freezing approach correctly addresses the previous critical review comment. Running the freeze code via vm.Script.runInContext(innerContext) ensures the inner VM's intrinsic prototypes are frozen (used by literals like '', []). The parent VM prototypes are also frozen because SafeObject.prototype = Object.prototype references them.

This is a clean implementation that provides defense-in-depth against prototype pollution attacks in both VM contexts.


926-970: Solid SafeObject implementation for property manipulation defense.

The SafeObject correctly blocks dangerous static methods (defineProperty, setPrototypeOf, etc.) while preserving commonly needed functionality (keys, values, freeze, etc.). Restricting Object.create to disallow property descriptors prevents property manipulation attacks while maintaining basic object creation capability.


977-977: SafeObject correctly integrated into safe globals.

The SafeObject replacement for the native Object is properly wrapped with createSecureProxy before injection into innerContext, maintaining the defense-in-depth approach.


1047-1047: Helpful clarification for maintainability.

The comment correctly notes where codeGeneration is configured, preventing future confusion about security option placement.


Comment @coderabbitai help to get the list of available commands and usage tips.

@frontegg-david
Copy link
Contributor Author

frontegg-david commented Jan 6, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI Agents
In @libs/ast-guard/src/rules/index.ts:
- Line 23: The public export ResourceExhaustionRule (export * from
'./resource-exhaustion.rule') was added but missing documentation; update the
docs by adding an entry for ResourceExhaustionRule in
docs/draft/docs/libraries/ast-guard.mdx that describes the rule, its purpose,
usage, and any config options or examples, ensuring the new documentation
follows the existing format and headings used for other rule entries in that MDX
file.

In @libs/enclave-vm/src/memory-proxy.ts:
- Around line 159-160: Remove the unused variable declaration const
originalToString = Array.prototype.toString from memory-proxy.ts (it’s declared
at the same spot as originalJoin) and ensure no other code references
originalToString; keep originalJoin as-is since toString delegates to
this.join(','). After removal, run lint/type checks to confirm no
unused-variable remains.
🧹 Nitpick comments (10)
libs/enclave-vm/src/__tests__/literal-constructor-escape.spec.ts (2)

25-38: Consider using try/finally or afterEach for reliable cleanup.

If any assertion fails, enclave.dispose() won't be called, potentially leaking resources across test runs. This pattern is repeated throughout the file.

Option 1: Use try/finally per test
     it('should block Function constructor from array literal', async () => {
       const enclave = new Enclave();
+      try {
         const code = `
           const c = 'con' + 'struc' + 'tor';
           const arr = [];
           const Fn = arr[c][c];
           return Fn('return 42')();
         `;
         const result = await enclave.run(code);
         expect(result.success).toBe(false);
         // Should fail at AST level (constructor obfuscation detected) or VM level (codeGeneration.strings disabled)
         expect(result.error?.message).toMatch(/code generation from strings|EvalError|AgentScript validation failed/i);
+      } finally {
         enclave.dispose();
+      }
     });
Option 2: Use describe-scoped variable with afterEach
describe('Array Literal Constructor Chain Attack', () => {
  let enclave: Enclave;

  afterEach(() => {
    enclave?.dispose();
  });

  it('should block Function constructor from array literal', async () => {
    enclave = new Enclave();
    // ... test code ...
  });
});

208-244: Consider asserting on failure cases for completeness.

The conditional assertions only verify behavior when result.success is true. If the code fails for an unexpected reason (e.g., syntax error), the test would silently pass.

🔎 Suggested improvement
       const result = await enclave.run(code);
       // Either blocked by SecureProxy or frozen prototype
       if (result.success) {
         expect((result.value as { polluted: boolean }).polluted).toBe(false);
+      } else {
+        // Verify failure is security-related, not an unexpected error
+        expect(result.error?.message).toMatch(/Security violation|AgentScript validation failed|frozen|not extensible/i);
       }
       enclave.dispose();
libs/enclave-vm/src/memory-proxy.ts (1)

165-197: Consider extracting shared join estimation logic to reduce duplication.

The join size estimation and limit-checking logic (lines 165-196) is nearly identical to the implementation in wrapArrayInstance (lines 53-84). This duplication could lead to maintenance drift if one is updated without the other.

Consider extracting a shared helper function:

🔎 Proposed refactor
// Helper at module level
function estimateJoinSize(arr: unknown[], separator: string): number {
  const arrLength = arr.length;
  if (arrLength > 10000) {
    return arrLength * (10 + separator.length) * 2;
  }
  let estimatedSize = 0;
  for (let i = 0; i < arrLength; i++) {
    const item = arr[i];
    estimatedSize += (item == null ? 0 : String(item).length) + separator.length;
  }
  return estimatedSize * 2;
}

function checkJoinLimit(tracker: MemoryTracker, estimatedSize: number): void {
  const limit = tracker.getLimit();
  if (limit > 0 && estimatedSize > limit) {
    throw new MemoryLimitError(
      `Array.join would exceed memory limit (estimated ${estimatedSize} bytes, limit ${limit} bytes)`,
      estimatedSize,
      limit,
    );
  }
}

Then both wrapArrayInstance and createTrackedArrayMethods can use these helpers.

libs/enclave-vm/src/__tests__/function-gadget-attacks.spec.ts (1)

55-66: Consider adding Security violation to the error pattern for consistency.

The error message regex only matches AgentScript validation failed|code generation from strings, but other test files also accept Security violation for runtime proxy blocks.

🔎 Proposed fix
 function expectSecureResult(
   result: { success: boolean; value?: unknown; error?: { message?: string } },
   expectedValue: unknown,
 ): void {
   if (!result.success) {
     // AST-level validation blocked the attack - this is valid and stronger security
-    expect(result.error?.message).toMatch(/AgentScript validation failed|code generation from strings/i);
+    expect(result.error?.message).toMatch(/Security violation|AgentScript validation failed|code generation from strings/i);
     return;
   }
   // Runtime blocking or sandbox execution
   expectSecureOutcome(result.value, expectedValue);
 }
libs/enclave-vm/src/__tests__/runtime-attack-vectors.spec.ts (1)

56-67: Helper signature differs from function-gadget-attacks.spec.ts - consider unifying.

This expectSecureResult accepts expectedValues: unknown[] (array), while the one in function-gadget-attacks.spec.ts accepts expectedValue: unknown (single value). Both are valid designs, but having consistent helper signatures across test files would improve maintainability.

Consider extracting these helpers to a shared test utility file to ensure consistency across the test suite.

libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts (2)

142-159: Test description is misleading - it tests iteration limits, not timeout.

The test name says "should enforce timeout or iteration limits" but the assertion specifically checks for iteration limit errors. Consider renaming for clarity or adding an actual timeout test.

🔎 Proposed fix
-      it('should enforce timeout or iteration limits', async () => {
-        // This test verifies that long-running code is interrupted
-        // by either timeout OR iteration limits - both are valid protections
+      it('should enforce iteration limits on computation-heavy loops', async () => {
+        // This test verifies that long-running code is interrupted by iteration limits
         const enclave = new Enclave({ timeout: 100, maxIterations: 100 });

579-592: Weak assertion - test only verifies no crash, not security behavior.

The assertion expect(result).toBeDefined() only confirms the system didn't crash. Consider strengthening to verify the attack was actually mitigated.

🔎 Proposed fix
       const result = await enclave.run(code);
       // Main assertion: we get a result (didn't crash)
-      // The result may be success or failure depending on implementation
+      // Either blocked or succeeded within memory bounds
       expect(result).toBeDefined();
+      if (result.success && typeof result.value === 'string') {
+        // If it succeeded, verify the string was created (test passed)
+        expect((result.value as string).length).toBeLessThanOrEqual(50 * 1024 * 1024);
+      }
       enclave.dispose();
libs/ast-guard/src/rules/resource-exhaustion.rule.ts (3)

67-77: BigInt comparison with number may lose precision for very large values.

The comparison exponent > maxBigIntExponent compares a BigInt with a number. While this works for values within safe integer range, consider making the comparison type-consistent.

🔎 Proposed fix
             // Check for large exponent
             if (node.right.type === 'Literal') {
               const exponent = node.right.bigint ? BigInt(node.right.bigint) : BigInt(node.right.value || 0);
-              if (exponent > maxBigIntExponent) {
+              if (exponent > BigInt(maxBigIntExponent)) {
                 context.report({
                   code: 'RESOURCE_EXHAUSTION',
                   message: `BigInt exponent ${exponent} exceeds maximum allowed (${maxBigIntExponent}). Large exponents can cause CPU exhaustion.`,

186-199: Missing __proto__ check in VariableDeclarator handler.

The isSuspiciousStringConcat method checks for __proto__, but the VariableDeclarator handler only reports constructor and prototype. Consider adding __proto__ for consistency.

🔎 Proposed fix
       VariableDeclarator: (node: any) => {
         if (!blockConstructorAccess) return;

         if (node.init && node.init.type === 'BinaryExpression') {
           const result = this.evaluateStringConcat(node.init);
-          if (result === 'constructor' || result === 'prototype') {
+          if (result === 'constructor' || result === 'prototype' || result === '__proto__') {
             context.report({
               code: 'CONSTRUCTOR_ACCESS',
               message: `Variable assigned to "${result}" via string concatenation. This is a potential sandbox escape vector.`,
               location: this.getLocation(node),
             });
           }
         }
       },

215-229: String concatenation evaluation is limited to simple literals - document the limitation.

The evaluateStringConcat method only evaluates direct string literal concatenations. Attackers could bypass this using template literals, String.fromCharCode, or variable references. This is acceptable given runtime protections exist, but consider documenting this limitation.

🔎 Proposed fix
   /**
    * Try to evaluate a string concatenation expression
    * Returns the result if it's a simple string concat, or null if too complex
+   *
+   * NOTE: This only handles direct string literal concatenation (e.g., 'con' + 'structor').
+   * More complex obfuscation (template literals, String.fromCharCode, variable references)
+   * is handled by runtime protections (SecureProxy, codeGeneration.strings=false).
    */
   private evaluateStringConcat(node: any): string | null {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6bda962 and e20bae1.

📒 Files selected for processing (19)
  • libs/ast-guard/src/presets/agentscript.preset.ts
  • libs/ast-guard/src/rules/index.ts
  • libs/ast-guard/src/rules/resource-exhaustion.rule.ts
  • libs/enclave-vm/src/__tests__/constructor-obfuscation-attacks.spec.ts
  • libs/enclave-vm/src/__tests__/double-vm.security.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.constructor-attack.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.nodejs24-security.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.security.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.serialization.spec.ts
  • libs/enclave-vm/src/__tests__/function-gadget-attacks.spec.ts
  • libs/enclave-vm/src/__tests__/literal-constructor-escape.spec.ts
  • libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts
  • libs/enclave-vm/src/__tests__/runtime-attack-vectors.spec.ts
  • libs/enclave-vm/src/adapters/vm-adapter.ts
  • libs/enclave-vm/src/adapters/worker-pool/worker-script.ts
  • libs/enclave-vm/src/double-vm/double-vm-wrapper.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
  • libs/enclave-vm/src/enclave.ts
  • libs/enclave-vm/src/memory-proxy.ts
🧰 Additional context used
📓 Path-based instructions (1)
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/enclave-vm/src/__tests__/enclave.serialization.spec.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
  • libs/enclave-vm/src/__tests__/runtime-attack-vectors.spec.ts
  • libs/ast-guard/src/rules/index.ts
  • libs/enclave-vm/src/__tests__/constructor-obfuscation-attacks.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.constructor-attack.spec.ts
  • libs/enclave-vm/src/__tests__/double-vm.security.spec.ts
  • libs/enclave-vm/src/adapters/worker-pool/worker-script.ts
  • libs/enclave-vm/src/memory-proxy.ts
  • libs/enclave-vm/src/__tests__/function-gadget-attacks.spec.ts
  • libs/enclave-vm/src/__tests__/literal-constructor-escape.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.security.spec.ts
  • libs/ast-guard/src/rules/resource-exhaustion.rule.ts
  • libs/enclave-vm/src/enclave.ts
  • libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.nodejs24-security.spec.ts
  • libs/enclave-vm/src/double-vm/double-vm-wrapper.ts
  • libs/enclave-vm/src/adapters/vm-adapter.ts
  • libs/ast-guard/src/presets/agentscript.preset.ts
🧬 Code graph analysis (5)
libs/enclave-vm/src/memory-proxy.ts (2)
libs/enclave-vm/src/index.ts (1)
  • MemoryLimitError (109-109)
libs/enclave-vm/src/memory-tracker.ts (1)
  • MemoryLimitError (40-58)
libs/enclave-vm/src/__tests__/literal-constructor-escape.spec.ts (1)
libs/enclave-vm/src/enclave.ts (1)
  • Enclave (157-739)
libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts (1)
libs/enclave-vm/src/enclave.ts (1)
  • Enclave (157-739)
libs/enclave-vm/src/__tests__/enclave.nodejs24-security.spec.ts (1)
libs/enclave-vm/src/enclave.ts (1)
  • Enclave (157-739)
libs/ast-guard/src/presets/agentscript.preset.ts (1)
libs/ast-guard/src/rules/resource-exhaustion.rule.ts (1)
  • ResourceExhaustionRule (32-239)
🔇 Additional comments (44)
libs/enclave-vm/src/__tests__/literal-constructor-escape.spec.ts (6)

1-22: Well-documented attack vector and defense strategy.

The header documentation clearly explains the constructor chain attack pattern and the two defense layers. This provides excellent context for understanding the test suite's purpose.


84-111: LGTM - Object literal attack vectors well covered.

The tests correctly verify blocking of Function constructor access via object literals and the Object.prototype chain.


128-144: Double VM configuration is appropriate.

The test correctly enables double VM mode with defaults and includes a toolHandler to exercise the full code path.


146-206: Good regression coverage for legitimate operations.

These tests ensure the security hardening doesn't break normal array, object, string, and Promise operations - essential for preventing false positives.


247-272: Well-documented skip with appropriate test configuration.

The comment clearly explains why the large Array.join test is skipped (single-VM mode requirement). The memory limit configuration and Jest timeout are reasonable.


274-299: LGTM - CPU exhaustion tests properly configured.

The skipped test documents the platform-dependency clearly, and the reasonable BigInt operations test ensures normal use cases work.

libs/enclave-vm/src/memory-proxy.ts (4)

10-10: LGTM!

Import correctly adds MemoryLimitError which is used in the new join implementations for pre-allocation limit checking.


46-99: Well-designed proxy wrapper for array memory protection.

The pre-allocation size check is a solid defense against memory exhaustion attacks like new Array(12_000_000).join('x').

Minor note: The separator length is added for each element (line 66), but join only inserts N-1 separators for N elements. This results in a slight overestimate by sep.length * 2 bytes, which is acceptable since overestimation is conservative for security purposes.


101-140: LGTM!

Consistent wrapping of array instances across all creation paths (apply, construct, Array.from, Array.of) ensures comprehensive memory tracking coverage.


200-203: LGTM!

Clean delegation to the tracked join method ensures toString also benefits from memory limit protection.

libs/enclave-vm/src/adapters/vm-adapter.ts (2)

387-394: LGTM! Critical sandbox hardening.

Adding codeGeneration: { strings: false, wasm: false } at context creation time is the correct approach to prevent dynamic code generation attacks. This blocks new Function() and eval() from string arguments, closing a significant sandbox escape vector via constructor chain traversal.


472-472: Good clarifying comment.

The comment correctly notes that codeGeneration must be set at createContext() time, not runInContext(). This is important documentation for future maintainers.

libs/enclave-vm/src/enclave.ts (2)

320-344: LGTM! Correct validation ordering.

Moving validation to run before sidecar/memory transforms is the right approach. This ensures malicious patterns like constructor obfuscation are detected in their original form, before they could be transformed into __safe_concat calls that might bypass detection.


346-354: LGTM! Transforms correctly deferred.

Applying sidecar and memory-tracking transforms only after successful validation is correct. This provides both security benefits (early rejection of malicious code) and performance benefits (no wasted transform work on invalid code).

libs/enclave-vm/src/__tests__/double-vm.security.spec.ts (5)

1185-1198: LGTM! Test expectations updated for dual-layer security.

The updated regex /Security violation|AgentScript validation failed/ correctly accommodates the dual-layer defense model where attacks can be blocked either at AST validation time or at runtime by the secure proxy. The comment update on line 1185 accurately reflects this.


1220-1222: Consistent with dual-layer security model.


1243-1245: Consistent with dual-layer security model.


1270-1272: Consistent with dual-layer security model.


1315-1317: Consistent with dual-layer security model.

libs/enclave-vm/src/__tests__/enclave.serialization.spec.ts (1)

143-143: LGTM! Consistent test expectation update.

The updated regex aligns with the dual-layer security model, where constructor access attempts can be blocked either during AST validation or at runtime by the secure proxy.

libs/enclave-vm/src/double-vm/double-vm-wrapper.ts (1)

192-199: LGTM! Consistent sandbox hardening in double VM wrapper.

Adding codeGeneration: { strings: false, wasm: false } to the parent VM context creation is consistent with the hardening applied in vm-adapter.ts. This ensures the defense-in-depth model is maintained, with both parent and inner VMs protected against dynamic code generation attacks.

libs/enclave-vm/src/adapters/worker-pool/worker-script.ts (1)

137-142: LGTM! Worker pool sandbox hardening complete.

Adding codeGeneration: { strings: false, wasm: false } to the worker pool's VM context completes the consistent hardening across all sandbox adapters (vm-adapter, double-vm-wrapper, and worker-script). This ensures that regardless of which execution path is used, dynamic code generation attacks are blocked.

libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (2)

715-719: LGTM! Strong sandbox hardening with codeGeneration restrictions.

Disabling dynamic code generation via strings: false, wasm: false is an effective defense-in-depth measure that prevents constructor-chain-based sandbox escapes like [][c][c]('malicious code'). The inline comment clearly explains the security rationale.


844-844: LGTM! Helpful clarification comment.

The comment accurately explains that codeGeneration constraints are configured at context creation time rather than during script execution. This aids code comprehension.

libs/enclave-vm/src/__tests__/enclave.constructor-attack.spec.ts (2)

29-29: LGTM! Test expectations correctly updated for dual-layer defense.

The regex pattern /Security violation|AgentScript validation failed/ appropriately accommodates both AST-level validation (via ResourceExhaustionRule) and runtime proxy blocking. This reflects the defense-in-depth approach where attacks may be blocked at either layer.

Also applies to: 47-47, 64-64, 81-81, 98-98, 115-115, 135-135, 189-189, 211-211, 237-237


158-166: LGTM! Well-documented dual-outcome test.

The conditional logic appropriately handles two valid security outcomes:

  1. AST validation blocks the suspicious string concatenation pattern
  2. Proxy invariant respected - JavaScript requires returning non-configurable properties

The inline comments clearly explain this is expected behavior, documenting the known limitation while still validating that the primary attack vectors remain blocked.

libs/ast-guard/src/presets/agentscript.preset.ts (2)

18-18: LGTM! Import correctly added.

The ResourceExhaustionRule import is properly placed alongside other validation rules.


434-446: LGTM! ResourceExhaustionRule properly integrated with sensible defaults.

The configuration provides effective defense against CPU/memory exhaustion attacks:

  • maxBigIntExponent: 10000 prevents exponential computation DoS
  • maxArraySize: 1000000 and maxStringRepeat: 100000 prevent memory exhaustion
  • blockConstructorAccess: true strengthens the dual-layer defense against sandbox escapes
  • blockBigIntExponentiation: false allows legitimate BigInt operations below the threshold

The inline comment clearly explains the rule's purpose, and the thresholds align with the library documentation provided.

libs/enclave-vm/src/__tests__/enclave.nodejs24-security.spec.ts (3)

129-129: LGTM! Consistent error pattern updates for dual-layer defense.

The regex pattern correctly accommodates both AST validation and runtime blocking paths, consistent with the broader test suite updates.

Also applies to: 142-142, 314-314, 328-328


151-168: LGTM! Properly documented proxy invariant test with dual outcomes.

The conditional logic appropriately handles AST-level blocking (new) vs. runtime proxy invariant behavior (existing limitation). The comments clearly explain why both outcomes are valid security responses.


174-198: LGTM! Tests appropriately isolate proxy-level behavior.

The validate: false option allows testing the runtime proxy configuration independently of AST validation. The comments clearly explain this testing strategy. However, note that this introduces a new public API parameter to the Enclave options.

Note: Based on the coding guidelines, since this is a publishable SDK library under libs/, the new validate parameter should be documented. Ensure there is a corresponding update in docs/draft/docs/** for this new public API option.

Also applies to: 214-236

libs/enclave-vm/src/__tests__/enclave.security.spec.ts (2)

893-893: LGTM! Consistent dual-layer defense error patterns.

The regex pattern correctly accommodates both AST validation and runtime proxy blocking, maintaining consistency across the test suite.

Also applies to: 911-911, 929-929, 1323-1323, 1344-1344


1321-1322: LGTM! Well-structured dual-outcome security tests.

The conditional expectations appropriately validate security across both defense layers:

  1. AST validation blocks suspicious patterns early (preferred outcome)
  2. Runtime proxy blocks if AST validation passes (fallback defense)

The addition of CONSTRUCTOR_ACCESS to the regex pattern at line 1435 correctly matches the error code from ResourceExhaustionRule. The comments accurately explain the dual-path security model.

Also applies to: 1342-1343, 1371-1377, 1403-1409, 1432-1435

libs/enclave-vm/src/__tests__/constructor-obfuscation-attacks.spec.ts (3)

40-40: LGTM - Error pattern correctly updated for dual-layer security.

The regex pattern /Security violation|AgentScript validation failed/ appropriately handles both runtime proxy blocking and AST-level validation outcomes.


513-537: Conditional test logic correctly handles both security outcomes.

The test appropriately branches on result.success to validate either:

  • AST validation blocking (error message matches pattern)
  • Runtime proxy allowing access in PERMISSIVE mode

The comment on lines 515-517 clearly documents why string concatenation attacks are blocked even in PERMISSIVE mode.


559-580: Test correctly isolates proxy configuration from AST validation.

Disabling validation (validate: false) to test secureProxyConfig behavior directly is a valid testing strategy that ensures the proxy layer can be tested independently.

libs/enclave-vm/src/__tests__/function-gadget-attacks.spec.ts (2)

42-49: Helper function correctly identifies blocked values as valid security outcomes.

The implementation is clear and the hardcoded blocked values array appropriately covers the test patterns used throughout the file.


380-388: Good defensive test structure handling both outcomes.

The conditional check correctly validates either sandbox execution or AST blocking, with appropriate assertions for each path.

libs/enclave-vm/src/__tests__/runtime-attack-vectors.spec.ts (2)

452-460: Thorough dual-outcome validation for async function constructor test.

The test correctly handles both AST blocking (via error message check) and runtime sandbox isolation (via regex non-match for host access). The comment clearly explains the security expectations.


595-667: Excellent documentation of known security limitation.

The test at line 595-651 explicitly documents that passing constructor functions (like Map) as globals can expose the host's Function constructor. The warning comment and console.warn are valuable for security awareness.

libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts (2)

1-18: Excellent documentation header.

The JSDoc clearly describes the defense layers (AST-level, runtime limits, VM timeout, worker watchdog), providing valuable context for understanding the test suite's purpose.


600-638: Sort attack test has appropriate timeout handling.

The test correctly uses Jest's extended timeout (15000ms) and validates that either the attack completes within reasonable time or is blocked for security reasons. The conditional assertion logic is appropriate for this scenario.

libs/ast-guard/src/rules/resource-exhaustion.rule.ts (2)

1-18: Well-designed options interface with sensible defaults.

The interface clearly documents each option with JSDoc comments, and the defaults balance security with usability.


32-47: Public API addition for libs/ - ensure docs are updated.

As per coding guidelines, changes to public APIs in libs/** should have matching documentation updates. Verify that ResourceExhaustionRule and ResourceExhaustionOptions are documented appropriately.

Based on coding guidelines, ensure there is a corresponding documentation update in docs/draft/docs/** for this new public API.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI Agents
In @libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts:
- Around line 785-799: The Object.freeze calls are being applied to the parent
VM globals; instead freeze the prototypes on the sandboxed context
(innerContext) so the inner VM’s prototypes are hardened—replace usages like
Object.freeze(Object.prototype) with
innerContext.Object.freeze(innerContext.Object.prototype) (and do the same for
Array.prototype, Function.prototype, String.prototype, Number.prototype,
Boolean.prototype, Date.prototype, Error.prototype, TypeError.prototype,
RangeError.prototype, SyntaxError.prototype, ReferenceError.prototype,
Promise.prototype) ensuring the freezes run inside innerContext rather than the
parent scope.
🧹 Nitpick comments (7)
docs/draft/docs/libraries/ast-guard.mdx (1)

80-134: Well-structured documentation for ResourceExhaustionRule.

The new Built-in Rules section covers all the key elements per the coding guidelines: detected patterns, configuration options, example usage, and blocked attack examples.

One optional addition: consider adding a brief note linking this rule to the AgentScript preset mentioned earlier (lines 32-38), since the referenced guidance suggests documenting "how to instantiate rules for the AgentScript preset." A single sentence noting that createAgentScriptPreset() includes this rule by default would help users understand when explicit configuration is needed versus when the preset handles it.

libs/enclave-vm/src/memory-proxy.ts (2)

60-69: Size estimation includes one extra separator.

The estimation adds sep.length for every element, but join only inserts n-1 separators for n elements. This results in a slight over-estimate (by one separator length). Since over-estimation is conservative and safe for limit checks, this is acceptable, but worth noting.

🔎 More precise calculation (optional)
           if (arrLength > 10000) {
              // Rough estimate for large arrays
-             estimatedSize = arrLength * (10 + sep.length) * 2;
+             estimatedSize = (arrLength * 10 + Math.max(0, arrLength - 1) * sep.length) * 2;
           } else {
             for (let i = 0; i < arrLength; i++) {
               const item = target[i];
-              estimatedSize += (item == null ? 0 : String(item).length) + sep.length;
+              estimatedSize += (item == null ? 0 : String(item).length);
+              if (i < arrLength - 1) estimatedSize += sep.length;
             }
             estimatedSize = estimatedSize * 2; // UTF-16
           }

164-196: Consider extracting shared join-estimation logic.

The size estimation and limit-check logic in wrapArrayInstance.join (lines 53-84) and createTrackedArrayMethods.join (lines 164-196) are nearly identical. Extracting a shared helper would reduce duplication and ensure consistent behavior if the estimation heuristics change.

🔎 Example helper extraction
function estimateJoinSize(arr: unknown[], separator: string): number {
  const sep = separator;
  const arrLength = arr.length;
  
  if (arrLength > 10000) {
    return arrLength * (10 + sep.length) * 2;
  }
  
  let size = 0;
  for (let i = 0; i < arrLength; i++) {
    const item = arr[i];
    size += (item == null ? 0 : String(item).length) + sep.length;
  }
  return size * 2;
}

function checkJoinLimit(tracker: MemoryTracker, estimatedSize: number): void {
  const limit = tracker.getLimit();
  if (limit > 0 && estimatedSize > limit) {
    throw new MemoryLimitError(
      `Array.join would exceed memory limit (estimated ${estimatedSize} bytes, limit ${limit} bytes)`,
      estimatedSize,
      limit,
    );
  }
}

Then both join implementations can call these helpers.

libs/enclave-vm/src/adapters/vm-adapter.ts (1)

376-444: Consider extracting shared constants to reduce duplication.

NODEJS_24_DANGEROUS_GLOBALS is duplicated verbatim in parent-vm-bootstrap.ts (lines 67-135). This creates a maintenance burden—if security levels are updated in one file, the other may become inconsistent.

Consider extracting this to a shared constants file (e.g., security-constants.ts) and importing it in both locations.

libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (1)

830-874: SafeObject logic duplicated from vm-adapter.ts.

The SafeObject creation (lines 841-874) duplicates the logic from createSafeObject in vm-adapter.ts. Since this is generated code, direct import isn't possible, but consider:

  1. Extracting the method lists (DANGEROUS_OBJECT_STATIC_METHODS, safeObjectMethods) to shared constants
  2. Generating the SafeObject code from a single source of truth to ensure consistency

This would reduce the risk of security fixes being applied to one location but not the other.

libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts (2)

471-504: Consider test timing reliability.

This test relies on timing assertions with generous margins (500ms timeout, <15s execution, 20s test timeout). While the margins help prevent flakiness, the test could still be sensitive to CI environment variability. The high maxIterations: 10000000 is intentional to test timeout rather than iteration limits.

Consider documenting why the specific timing values were chosen, or if the elapsed time assertion at line 500 is strictly necessary for the test's purpose.


898-906: Consider simplifying complex conditional assertion.

The assertion logic at lines 901-905 is complex with substring checking and conditional expectations. This could be refactored for clarity.

Suggested simplification
-      expect(['parsed', 'error: Maximum call stack size exceeded']).toContain(
-        result.value?.toString().substring(0, 6) === 'error:'
-          ? 'error: Maximum call stack size exceeded'
-          : result.value,
-      );
+      const value = result.value?.toString() || '';
+      expect(value === 'parsed' || value.startsWith('error:')).toBe(true);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e20bae1 and cbe94a2.

📒 Files selected for processing (6)
  • docs/draft/docs/libraries/ast-guard.mdx
  • docs/live/docs/libraries/ast-guard.mdx
  • libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts
  • libs/enclave-vm/src/adapters/vm-adapter.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
  • libs/enclave-vm/src/memory-proxy.ts
🧰 Additional context used
📓 Path-based instructions (3)
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/enclave-vm/src/memory-proxy.ts
  • libs/enclave-vm/src/adapters/vm-adapter.ts
  • libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
docs/**

⚙️ CodeRabbit configuration file

docs/**: Repository documentation for the SDK, using MDX and hosted by Mintlify. See more specific rules for: - docs/docs/** (latest rendered docs, automation-only) - docs/v/** (archived versions, read-only) - docs/draft/docs/** (human-editable drafts) - docs/blogs/** (blogs, human edited) - docs/docs.json (Mintlify navigation)

Files:

  • docs/live/docs/libraries/ast-guard.mdx
  • docs/draft/docs/libraries/ast-guard.mdx
docs/draft/docs/**

⚙️ CodeRabbit configuration file

docs/draft/docs/**: This folder holds the draft/source docs that humans are expected to edit. When authors want to add or change documentation, they should do it here. The Codex workflow uses these drafts, together with the code diff, to generate the latest docs under docs/docs/. As a reviewer: - Encourage contributors to add/update content here instead of docs/docs/. - It is fine to do structural/content feedback here (clarity, examples, etc).

Files:

  • docs/draft/docs/libraries/ast-guard.mdx
🧬 Code graph analysis (3)
libs/enclave-vm/src/memory-proxy.ts (1)
libs/enclave-vm/src/memory-tracker.ts (1)
  • MemoryLimitError (40-58)
libs/enclave-vm/src/adapters/vm-adapter.ts (1)
libs/enclave-vm/src/types.ts (1)
  • SecurityLevel (24-24)
libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (2)
libs/enclave-vm/src/index.ts (1)
  • SecurityLevel (28-28)
libs/enclave-vm/src/types.ts (1)
  • SecurityLevel (24-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Performance
  • GitHub Check: Test
🔇 Additional comments (19)
docs/live/docs/libraries/ast-guard.mdx (1)

83-137: Verify if direct edits to live docs follow the intended workflow.

Per the coding guidelines, docs/docs/** is described as "latest rendered docs, automation-only," and contributors are encouraged to add/update content in docs/draft/docs/** instead. The Codex workflow is meant to generate live docs from drafts combined with code diffs.

If this file is being edited directly alongside the draft, please confirm this is intentional and won't be overwritten by automation. Otherwise, consider removing changes from this file and relying on the draft-to-live generation workflow.

libs/enclave-vm/src/memory-proxy.ts (5)

10-10: LGTM!

The MemoryLimitError import is correctly added and aligns with the class definition in memory-tracker.ts.


204-249: Arrays from prototype methods are not wrapped.

Arrays created via concat, slice, splice, map, filter, flatMap, and flat are tracked for size but not wrapped with wrapArrayInstance. This means calling .join() on these result arrays would use the untracked native join method, potentially bypassing the memory limit pre-check.

If an attacker can create a large array via one of these methods and then call join() on it, the pre-allocation check in wrapArrayInstance wouldn't apply.

Consider whether these methods should also return wrapped arrays:

     concat: function (this: unknown[], ...items: unknown[]) {
       const result = originalConcat.apply(this, items);
       tracker.trackArray(result.length);
-      return result;
+      return wrapArrayInstance(result);
     },

Note: This would require wrapArrayInstance to be accessible in createTrackedArrayMethods, possibly by passing it as a parameter or defining it at module scope.


198-202: LGTM!

The toString implementation correctly delegates to the tracked join method via this.join(','), ensuring memory limits are enforced consistently. The previously flagged unused originalToString variable has been removed.


64-67: String(item) during estimation may trigger getters or toString() methods.

Calling String(item) on each array element during size estimation could invoke user-defined toString() methods or Proxy getters. In adversarial scenarios, this might:

  • Cause side effects before the limit check
  • Allow expensive operations to run during estimation
  • Trigger recursive memory allocations

Since this is sandbox code, verify that the execution context limits what toString() can do, or consider using a more defensive approach for the rough estimate path.

Also applies to: 176-178


45-139: Good addition of memory limit enforcement for array operations.

The wrapArrayInstance wrapper and its integration into all array creation paths (apply, construct, from, of) provide comprehensive protection against memory exhaustion via join() attacks. The pre-allocation limit check is a sound defense-in-depth approach.

libs/enclave-vm/src/adapters/vm-adapter.ts (4)

275-362: Well-designed SafeObject mechanism for blocking property manipulation attacks.

The createSafeObject function correctly blocks dangerous static methods like defineProperty and setPrototypeOf while preserving safe methods. The implementation handles both Object() and new Object() call patterns.

Minor note: The function is not exported, but the AI summary indicates it should be "exposed." If this is intended for use by other modules (e.g., double-vm bootstrap), consider exporting it to avoid code duplication.


484-496: LGTM!

The SafeObject injection correctly uses the host's Object constructor to create a clean, untampered safe version that shadows the VM's internal Object global. The writable: false, configurable: false properties prevent runtime overrides.


549-556: LGTM!

The codeGeneration: { strings: false, wasm: false } setting is correctly placed at createContext time. This provides V8-level protection against new Function() and eval() from strings, complementing the global removal as defense-in-depth.


564-574: LGTM!

The guard if (key in baseSandbox) continue correctly prevents overwriting the SafeObject that was already injected by sanitizeVmContext. This ensures the security-hardened Object global is preserved.

libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (3)

776-780: LGTM!

The inner VM context is correctly created with codeGeneration: { strings: false, wasm: false } to block dynamic code execution at the V8 level.


877-902: LGTM!

SafeObject is correctly wrapped with createSecureProxy before injection into safeGlobals, providing defense-in-depth by combining the SafeObject restrictions with the secure proxy's property blocking.


950-955: LGTM!

The comment correctly clarifies that codeGeneration is configured in createContext(), not runInContext(). This documentation helps future maintainers understand the security architecture.

libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts (6)

1-58: LGTM: Well-documented test suite with good coverage of BigInt exponentiation limits.

The documentation header clearly explains the defense layers, and the BigInt exponentiation tests provide good coverage of both blocked and allowed scenarios. The consistent use of dispose() ensures proper cleanup.


600-668: LGTM: Thorough coverage of native sort attack vectors.

The Sort Attack tests appropriately handle the complexity of testing native code execution, with conditional assertions that accept either successful completion or security blocking. The tests verify both AST-level detection (large arrays) and runtime defense (iteration counting in callbacks).


678-795: Excellent defense-in-depth testing for constructor escape vectors.

The ATK-ESC-01 test suite comprehensively covers multiple constructor leak vectors (arrow functions, object methods, class methods, bound functions) and verifies both AST-level and runtime defenses. The test at lines 694-709 that explicitly disables validation to test runtime-only defense is particularly valuable.


1001-1186: Comprehensive serialization hijack coverage with good legitimate-use verification.

The ATK-DATA-02 tests thoroughly verify that metaprogramming APIs (defineProperty, setPrototypeOf, etc.) are blocked while ensuring safe Object methods (keys, values, entries, freeze, isFrozen) remain available. The test at lines 1129-1156 using toolHandler is particularly good at validating defense-in-depth.


1199-1479: Critical security verification: dangerous globals removal at VM level.

The ATK-RECON-01 test suite provides essential verification that dangerous globals (Function, eval, Proxy, Reflect, etc.) are removed from the VM context even when AST validation is disabled. The tests at lines 1442-1477 comprehensively verify all dangerous globals are undefined while essential globals remain available. This is a critical security boundary test.


19-1479: Only 3 of 95 tests have custom timeouts—the suite structure is appropriate.

The test suite contains 95 test cases, but only 3 explicitly configure Jest timeouts: one at 10000ms, one at 15000ms, and one at 20000ms (lines 159, 503, 638). The remaining 92 tests use Jest's default 5-second timeout. These custom timeouts are appropriately scoped to resource-exhaustion integration tests (worker pool termination, sort attacks, deep nesting) that require additional time for realistic attack scenarios. The jest.config.ts does not override the default timeout, and no performance concerns are documented in the CI workflow or recent commits.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI Agents
In @libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts:
- Around line 785-850: The memory-safe prototype patching is executed after the
sanitization (via ${sanitizeContextCode}), which conflicts with vm-adapter's
requirement to run the patch BEFORE sanitizeVmContext/SafeObject replacement;
move the patch generation/run (the patchCode + new
vm.Script(...).runInContext(innerContext) block that patches
stringProto/arrayProto) so it executes prior to injecting
${sanitizeContextCode}, ensuring the injection runs while Object.getPrototypeOf
still refers to the realm intrinsics and before Object is replaced by
SafeObject.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbe94a2 and 99b9e3e.

📒 Files selected for processing (4)
  • libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts
  • libs/enclave-vm/src/adapters/vm-adapter.ts
  • libs/enclave-vm/src/double-vm/double-vm-wrapper.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/enclave-vm/src/double-vm/double-vm-wrapper.ts
🧰 Additional context used
📓 Path-based instructions (1)
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/enclave-vm/src/adapters/vm-adapter.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
  • libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts
🧬 Code graph analysis (2)
libs/enclave-vm/src/adapters/vm-adapter.ts (2)
libs/enclave-vm/src/index.ts (1)
  • SecurityLevel (28-28)
libs/enclave-vm/src/types.ts (1)
  • SecurityLevel (24-24)
libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts (1)
libs/enclave-vm/src/enclave.ts (1)
  • Enclave (157-739)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Performance
  • GitHub Check: Test
🔇 Additional comments (29)
libs/enclave-vm/src/__tests__/resource-exhaustion.spec.ts (16)

1-18: Excellent documentation and clear defense-layer explanation.

The header comment provides a comprehensive overview of the test suite's purpose and the multi-layered defense strategy. This helps reviewers and maintainers understand the security model being tested.


24-58: Well-structured boundary testing for BigInt exponentiation.

The tests properly cover both blocking cases (exceeding limits) and allowing cases (within limits), with correct disposal patterns and appropriate assertions.


60-86: LGTM! Comprehensive infinite loop detection.

The tests cover the main infinite loop patterns (while(true), for(;;), while(1)) that should be blocked at the AST level.


93-140: Solid iteration limit enforcement testing.

The tests verify runtime iteration counting across different loop types (for, for-of) with both blocking and allowing scenarios.


142-161: LGTM! Appropriate test for multi-layer protection.

The test correctly verifies that iteration limits provide protection, with a safety timeout. The expectation aligns with the configured limits (iteration limit of 100 will be hit before timeout).


166-216: Thorough AST-level memory exhaustion detection.

The tests properly verify that large allocations (arrays, string repeats, Array.join) are blocked at the AST level while reasonable sizes are allowed.


221-250: Runtime memory limit enforcement well-tested.

The tests verify memory tracking works at runtime for exponential string growth while allowing normal operations within limits.


255-362: Comprehensive constructor obfuscation attack coverage.

The tests thoroughly verify blocking of various constructor access patterns, including direct access, computed properties, string concatenation, and prototype/proto access. All major escape vectors are covered.


367-396: Appropriate code generation blocking tests.

The tests correctly handle dual-layer defenses (AST and runtime) for Function constructor and eval, with flexible assertions that work for both blocking mechanisms.


401-466: Essential sanity checks for legitimate code paths.

These tests are critical to ensure the security measures don't break normal, safe operations. Good coverage of common patterns (arrays, objects, strings, BigInt, iteration).


471-504: LGTM! Critical integration test for worker termination.

This test verifies the watchdog timeout mechanism can forcefully terminate unresponsive workers, which is essential for preventing stuck processes. The timeout configuration (500ms worker timeout, 20s test timeout, <15s elapsed check) provides appropriate safety margins.


507-526: Clear unit tests for AST rule behavior.

These focused unit tests specifically verify the ResourceExhaustionRule's BigInt detection logic, separate from the broader integration tests.


534-668: Excellent real-world attack scenario coverage.

The ATK-MEM-01 tests cover multiple variations of the "Billion Laughs" memory bomb, including literal values, computed expressions, and iteration-based attacks. The Sort Attack tests verify protection against native code exploitation. The key assertion that the system doesn't crash (line 590) is particularly important.


678-1039: Comprehensive coverage of sophisticated attack vectors.

The ATK-ESC-01 tests thoroughly cover constructor escape techniques with both AST and runtime defenses tested separately. The template literal injection tests (ATK-TPL-01) verify that transforms apply inside ${} expressions. The JSON bomb tests (ATK-JSON-02/03) appropriately focus on "no crash" assertions rather than just blocking, which is the right approach for native code attacks.


1047-1587: Exceptional comprehensive security testing with defense-in-depth validation.

The ATK-BRIDGE-04 and ATK-DATA-02 tests thoroughly cover metaprogramming attack vectors (defineProperty, getters, setPrototypeOf, etc.) with excellent verification that safe Object methods remain functional (lines 1210-1235). The tool result defense test (lines 1237-1264) is particularly clever in testing runtime protection even when a tool returns a dangerous method name.

The ATK-RECON-01 suite is exemplary in its approach: using validate: false to specifically isolate and test VM-level defenses separate from AST validation, with clear comments explaining the dual-layer strategy (lines 1302-1306). The comprehensive checking of all dangerous globals (lines 1550-1585) provides strong verification that the VM context is properly sanitized.


1-1587: Outstanding comprehensive test suite for resource exhaustion prevention.

This test file demonstrates exceptional security engineering practices:

Strengths:

  1. Comprehensive Attack Coverage: Tests cover real-world attack scenarios (ATK-MEM-01 Billion Laughs, ATK-ESC-01 Constructor Leak, ATK-JSON-02/03 Parser Bombs, ATK-BRIDGE-04 Zombie Object, ATK-DATA-02 Serialization Hijack, ATK-RECON-01 Global Reconnaissance) with clear documentation of each attack vector.

  2. Defense-in-Depth Validation: Tests systematically verify multiple layers (AST validation, runtime limits, VM context sanitization) both together and in isolation (using validate: false to test runtime defenses specifically).

  3. Proper Resource Management: Every test properly disposes the Enclave instance—no resource leaks detected.

  4. Realistic Scenarios: Attack scenarios use actual exploitation techniques (string concatenation obfuscation, computed property access, template literal injection) rather than just testing APIs directly.

  5. Sanity Checks: Includes tests verifying legitimate code still works (lines 401-466, 1210-1235), which is essential for avoiding false positives.

  6. Flexible Assertions: Error message patterns accommodate dual failure paths (AST vs. runtime blocking), making tests robust across implementation changes.

Minor Observations:

  • Test timeouts are appropriately generous (10s-20s) for integration tests involving worker pools
  • The "no crash" assertions for JSON bombs (lines 590, 926, 948) are the correct approach for native code attacks where blocking may not be possible
  • The use of validate: false is well-justified in comments (lines 1302-1306) to isolate VM-level defenses

This test suite provides excellent protection against regression and strong confidence in the security posture of the Enclave VM.

libs/enclave-vm/src/adapters/vm-adapter.ts (8)

275-293: LGTM! Well-documented dangerous methods list.

The list of dangerous Object static methods is comprehensive and correctly focuses on static methods. The comment correctly notes that __defineGetter__ etc. are instance methods on Object.prototype, not static methods, so they're handled separately.


364-444: LGTM! Comprehensive dangerous globals expansion.

The expanded NODEJS_24_DANGEROUS_GLOBALS lists are well-organized by risk category and security level. The defense-in-depth approach is sound—even though codeGeneration.strings=false blocks new Function(), removing Function entirely eliminates future bypass vectors.

The categorization is clear:

  • Code execution (Function, eval, globalThis)
  • Metaprogramming (Proxy, Reflect)
  • Memory/timing attacks (SharedArrayBuffer, Atomics, gc)
  • Future APIs (ShadowRealm, WeakRef, FinalizationRegistry, etc.)

484-496: LGTM! SafeObject injection correctly shadows VM's Object.

The SafeObject is correctly injected into the VM context after dangerous globals are removed. The use of Object.defineProperty with writable: false and configurable: false ensures sandbox code cannot override this protection.


548-556: LGTM! Code generation restrictions correctly configured.

The codeGeneration: { strings: false, wasm: false } option is correctly set at vm.createContext() time, which prevents sandbox escape via new Function() and eval() from strings, as well as WebAssembly attacks.


558-631: LGTM! Memory-safe prototype patching with correct ordering.

The memory-safe prototype patches are correctly applied before sanitizeVmContext, which is critical because sanitizeVmContext replaces the intrinsic Object with SafeObject. The patches need access to the intrinsic Object.getPrototypeOf to reach the VM realm's actual String.prototype and Array.prototype.

The pre-allocation checks for repeat(), join(), padStart(), and padEnd() provide effective defense against memory exhaustion attacks by estimating size before allocation.


639-642: LGTM! Correct skip logic to preserve SafeObject.

The check if (key in baseSandbox) continue; correctly prevents overwriting the SafeObject that was already added by sanitizeVmContext. This maintains the security boundary.


712-712: LGTM! Helpful clarification comment.

The comment correctly notes that codeGeneration is configured at createContext() time, not runInContext(), which is an important distinction for developers maintaining this code.


304-362: SafeObject implementation is correct and intentional.

The use of the host realm's Object internally is by design and safe. The SafeObject wrapper controls all exposed methods and properly blocks property manipulation attacks:

  • Dangerous static methods (defineProperty, setPrototypeOf, getOwnPropertyDescriptor, getOwnPropertyDescriptors) are blocked with helpful error messages
  • Only safe methods (keys, values, entries, assign, freeze, etc.) are copied to SafeObject
  • Object.create is restricted to disallow property descriptors as the second argument
  • The prototype is correctly aliased from the VM context

Internal delegation to host Object (lines 311, 348) returns only converted primitives, never host realm objects. Tests confirm Object.defineProperty is properly blocked at runtime, preventing serialization hijack attacks (ATK-DATA-02) and prototype pollution. No escape vectors exist.

libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (5)

56-135: Consistent dangerous globals list across VM layers.

The NODEJS_24_DANGEROUS_GLOBALS lists are consistent with the implementation in vm-adapter.ts, which is good for defense-in-depth. Both the outer VM adapter and the parent VM bootstrap apply the same security restrictions.

Note: This is code duplication, but appears necessary since this file generates bootstrap code that runs in a separate VM context.


775-780: LGTM! Consistent code generation restrictions.

The innerContext is correctly created with codeGeneration: { strings: false, wasm: false }, consistent with the implementation in vm-adapter.ts.


897-941: LGTM! SafeObject implementation consistent with vm-adapter.ts.

The SafeObject implementation in the parent VM bootstrap matches the pattern in vm-adapter.ts, blocking dangerous static methods while preserving safe operations.


948-948: LGTM! SafeObject correctly added to safeGlobals.

The SafeObject is correctly wrapped in createSecureProxy and added to the safeGlobals map, which will shadow the native Object in innerContext.


1018-1018: LGTM! Helpful clarification comment.

The comment correctly clarifies that codeGeneration is configured at createContext() time, consistent with vm-adapter.ts.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI Agents
In @libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts:
- Around line 776-783: The memory-safe prototype patching must run before
sanitization: locate the innerContext creation (var innerContext =
vm.createContext(...)) and the subsequent memory-safe prototype patching block
(the code that patches Object/Array/Function prototypes to prevent memory
tampering), and move that entire patching block so it executes immediately after
innerContext is created and before the injected ${sanitizeContextCode} runs;
keep the sanitizeContextCode invocation after the patching to match
vm-adapter.ts ordering and preserve expected behavior.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99b9e3e and a298952.

📒 Files selected for processing (2)
  • libs/enclave-vm/src/__tests__/enclave.infinite-loop-attacks.spec.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
🧰 Additional context used
📓 Path-based instructions (1)
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/enclave-vm/src/__tests__/enclave.infinite-loop-attacks.spec.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
🧬 Code graph analysis (1)
libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (2)
libs/enclave-vm/src/index.ts (1)
  • SecurityLevel (28-28)
libs/enclave-vm/src/types.ts (1)
  • SecurityLevel (24-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Performance
  • GitHub Check: Test
🔇 Additional comments (8)
libs/enclave-vm/src/__tests__/enclave.infinite-loop-attacks.spec.ts (2)

485-506: LGTM! Test expectations correctly updated to reflect prototype freezing security enhancement.

The updated expectations are correct. With frozen prototypes, the custom circular toString method is effectively ignored, and V8 falls back to the default Object.prototype.toString, which safely returns '[object Object]' without infinite recursion. This demonstrates that the attack vector is successfully neutralized at runtime.


508-530: LGTM! Test expectations correctly updated to reflect prototype freezing security enhancement.

The updated expectations are correct. With frozen prototypes, the custom circular valueOf method is effectively ignored, and V8 falls back to the default Object.prototype.valueOf. When the returned object is coerced to a number using the unary + operator, it correctly results in NaN. This demonstrates that the attack vector is successfully neutralized at runtime.

libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (6)

58-135: Documentation improvements look good.

The enhanced comments clearly explain the security rationale for removing each dangerous global at different security levels. The defense-in-depth explanation for codeGeneration.strings=false combined with Function removal is particularly valuable.


785-850: Memory patching implementation is solid.

The approach of getting prototypes from literals ("" and []) correctly targets the realm's intrinsic prototypes. The pre-allocation memory checks for repeat, join, padStart, and padEnd effectively prevent memory exhaustion attacks like ATK-JSON-03.


852-895: Dual-context prototype freezing correctly implemented.

The code now properly freezes prototypes in both contexts:

  1. Parent VM prototypes (lines 863-875): Necessary because SafeObject.prototype is assigned to the parent VM's Object.prototype (line 961), and user code accessing Object.prototype in the inner VM reaches this parent prototype via the SafeObject proxy.

  2. Inner VM prototypes (lines 877-895): Freezes the intrinsic prototypes used by literals ("", [], etc.) within innerContext by executing a freeze script inside that context.

This defense-in-depth approach prevents prototype pollution attacks from both access paths.


926-970: SafeObject implementation is well-designed.

The SafeObject wrapper correctly blocks dangerous static methods (defineProperty, defineProperties, setPrototypeOf, etc.) while exposing a curated set of safe operations. The restricted Object.create that disallows property descriptors is particularly important for preventing property manipulation attacks like ATK-DATA-02.


977-977: Correct usage of SafeObject in innerContext.

Replacing the standard Object with the wrapped SafeObject in the inner VM's global scope ensures that all user code accesses to Object go through the security layers: SafeObject restrictions → SecureProxy → frozen prototypes.


1047-1047: Helpful clarification comment.

This comment correctly notes that the codeGeneration restrictions are configured during createContext() (line 779), not at the runInContext() call site, preventing potential confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants