Skip to content

Latest commit

Β 

History

History
553 lines (392 loc) Β· 15.3 KB

File metadata and controls

553 lines (392 loc) Β· 15.3 KB

Deep Audit, Review & Gap Analysis

Repository: rules-machine Date: April 6, 2026 Version: 1.6.0 Auditor: AI Code Review Agent


Executive Summary

This is a mature, well-structured JSON rules engine library for Node.js and browsers. The codebase demonstrates solid engineering practices with comprehensive test coverage, TypeScript typing, and multi-format build output. However, several areas require attention for modern standards and security hardening.

Overall Health: Good (7/10)

Category Score Status
Code Quality 8/10 Good
Security 6/10 Needs Work
Testing 8/10 Good
Documentation 9/10 Excellent
Dependencies 5/10 Critical
CI/CD 4/10 Needs Work
TypeScript 7/10 Good

Critical Findings

[CRITICAL-01] Severely Outdated Dependencies

Category: Security / Maintenance Severity: Critical

Description: Multiple core dependencies are significantly outdated with known security vulnerabilities:

Package Current Latest Risk
jest 26.x.x 30.x High
ts-jest 26.x.x 29.x High
typescript 4.8.4 5.8.x Medium
eslint 8.26.0 9.x Medium
lodash 4.17.21 4.17.21+ Known CVEs
debug 4.3.3 4.4.x Low

Impact:

  • Known security vulnerabilities in test dependencies could affect CI/CD pipeline
  • Missing security patches and performance improvements
  • Compatibility issues with modern Node.js versions

Remediation:

# Update package.json devDependencies
"devDependencies": {
  "jest": "^29.7.0",
  "ts-jest": "^29.2.0",
  "typescript": "^5.8.0",
  "eslint": "^9.0.0",
  "@typescript-eslint/eslint-plugin": "^8.0.0",
  "@typescript-eslint/parser": "^8.0.0"
}

[CRITICAL-02] Outdated CI/CD Pipeline

Category: DevOps / Security Severity: Critical

Location: .github/workflows/test.yml

Description: The GitHub Actions workflow uses severely outdated action versions:

  • actions/checkout@v2 (current: v4)
  • actions/setup-node@v2 (current: v4)
  • Only tests Node.js 14.x (EOL since April 2023)

Impact:

  • Security vulnerabilities in outdated action runners
  • No testing on modern Node.js LTS versions (18, 20, 22)
  • Potential CI/CD supply chain attacks

Remediation:

name: test
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18.x, 20.x, 22.x]

    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'yarn'
      - run: yarn install --frozen-lockfile
      - run: yarn lint
      - run: yarn test

[HIGH-01] Prototype Pollution Attack Surface

Category: Security Severity: High

Location: src/index.ts:479-499 (checkInvalidKeys)

Description: While checkInvalidKeys blocks dangerous keys like __proto__, constructor, and prototype, the protection is incomplete:

  1. Only validates top-level input keys
  2. Does not protect against nested prototype pollution via rule expressions
  3. The parser.expressionToValue() could be exploited with crafted expressions

Evidence:

function checkInvalidKeys<TInput extends object>(data: TInput) {
  const dangerousKeys = [
    '__proto__', 'prototype', 'constructor', 'toString',
    'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
  ];
  // Only checks Object.keys(data) - shallow check only
  const unsafeKeys = Object.keys(data).filter((key) =>
    dangerousKeys.includes(key),
  );

Impact:

  • Potential prototype pollution via nested objects in rules
  • Could lead to remote code execution in server environments
  • Bypass of security controls

Remediation:

  1. Implement deep key validation recursively
  2. Use Object.create(null) for all object creation
  3. Add runtime checks in evaluateRule and expression parser
  4. Consider using a library like deepmerge with prototype pollution protection

[HIGH-02] Unsafe Expression Parser Integration

Category: Security Severity: High

Location: src/index.ts:88-118, src/expression-language/index.ts

Description: The codebase uses expressionparser package for parsing expressions. While it claims to avoid eval, the expression parser still executes arbitrary code through function calls:

  1. User-provided strings are parsed and executed as expressions
  2. The THROW function allows arbitrary error messages (potential DoS)
  3. No sandboxing or resource limits on expression execution

Evidence:

const parser = init(ruleExpressionLanguage, (term: string) => {
  // term comes from user input via rules
  const result = extractValueOrLiteral(input, term, ...) ?? get(input, term, ...)
  return result;
});

Impact:

  • Denial of Service via complex expressions (ReDoS-like attacks)
  • Information disclosure through error messages
  • Potential code execution if expressionparser has vulnerabilities

Remediation:

  1. Add expression complexity limits (max depth, max operations)
  2. Implement timeout mechanisms for rule execution
  3. Whitelist allowed functions explicitly
  4. Add input sanitization before parsing

[HIGH-03] Missing Input Validation on Rule Structures

Category: Security Severity: High

Location: src/index.ts:120-330 (handleRule)

Description: The handleRule function trusts the structure of incoming rules without comprehensive validation:

  1. No maximum recursion depth for nested rules
  2. No validation of rule object structure before processing
  3. Type coercion happens implicitly in many places

Impact:

  • Stack overflow via deeply nested rules
  • Unexpected behavior from malformed rule objects
  • Potential for rule injection attacks

Remediation:

function validateRule(rule: unknown, depth = 0): asserts rule is Rule {
  const MAX_DEPTH = 50;
  if (depth > MAX_DEPTH)
    throw new UserError('Maximum rule nesting depth exceeded');

  if (typeof rule === 'string') return;
  if (Array.isArray(rule)) {
    rule.forEach((r) => validateRule(r, depth + 1));
    return;
  }
  if (typeof rule !== 'object' || rule === null) {
    throw new UserError('Invalid rule type');
  }
  // Validate specific rule types...
}

[MEDIUM-01] Inadequate Error Handling

Category: Code Quality Severity: Medium

Location: src/utils/errors.ts

Description: The UserError class suppresses stack traces completely:

get stack() {
  return '';  // Always returns empty string
}

Impact:

  • Difficult debugging in production
  • No error tracing for support teams
  • Loss of valuable debugging context

Remediation:

export class UserError extends Error {
  name = 'UserError';
  isUserError = true;

  constructor(message: string, options?: { cause?: unknown }) {
    super(message, options);
  }
}

// In error handling:
catch (e) {
  if (e instanceof UserError) {
    // Log without stack
    logger.warn(e.message);
  } else {
    // Log full stack for unexpected errors
    logger.error('Unexpected error:', e);
  }
}

[MEDIUM-02] Inconsistent TypeScript Strictness

Category: Code Quality Severity: Medium

Location: src/index.ts, tsconfig.json

Description: While strict: true is enabled, there are multiple @ts-expect-error comments and any types:

// src/index.ts:307
// @ts-expect-error
set(input, rule.set, arrayResult);

// src/index.ts:361
// @ts-expect-error: todo: fix this, add proper type for Result
results.runTime = performance.now() - startTime;

Impact:

  • Reduced type safety guarantees
  • Potential runtime errors not caught at compile time
  • Technical debt accumulation

Remediation:

  1. Remove all @ts-expect-error comments with proper fixes
  2. Replace any types with proper type definitions
  3. Enable noImplicitAny if not already enabled

[MEDIUM-03] Reserved Key Validation Bypass

Category: Security Severity: Medium

Location: src/index.ts:479-499

Description: The checkInvalidKeys function only runs once at the beginning of rule execution. The special keys $item, $index, $array are protected, but they're injected during array operations:

Object.assign(input, { $item: item, $index: index, $array: data });

Impact:

  • If rules could be injected mid-execution, reserved keys could be exploited
  • No validation that input doesn't shadow these keys before array operations

Remediation:

  1. Check for reserved keys before each array operation
  2. Use a separate scope object for iteration variables
  3. Document reserved keys prominently in README

[LOW-01] Performance: Missing Memoization

Category: Performance Severity: Low

Location: src/expression-language/index.ts

Description: Functions like DATEISO, DATE are called repeatedly without caching:

DATEISO: (arg) => {
  const dateArg = arg();
  // Creates new Date every time, even for same input
  return new Date(dateParser(dateArg)).toISOString();
};

Impact:

  • Unnecessary object allocation for repeated calls
  • Performance degradation in high-throughput scenarios

Remediation:

  • Add LRU cache for date parsing results
  • Consider memoizing pure function results

[LOW-02] Documentation Gaps

Category: Documentation Severity: Low

Description: While the README is comprehensive, several gaps exist:

  1. No security considerations section
  2. Missing performance benchmarks
  3. No guidance on rule complexity limits
  4. No examples of error handling patterns

Remediation: Add sections to README.md:

  • Security Considerations
  • Performance Guidelines
  • Error Handling Best Practices
  • Rule Complexity Recommendations

Positive Observations

  1. No eval/Function usage: The codebase explicitly avoids eval() and Function() constructors, using a proper expression parser instead.

  2. Comprehensive test coverage: Good test coverage with snapshots for trace output verification.

  3. Clean architecture: Well-organized separation of concerns between expression language, utils, and main logic.

  4. Multi-format builds: Supports CJS, ESM, and IIFE formats for broad compatibility.

  5. Good type definitions: TypeScript types are exported and generally well-defined.

  6. Trace functionality: Built-in tracing for debugging rule execution flow.

  7. Reserved key protection: Attempts to prevent prototype pollution via dangerous key blocking.


Systemic Patterns

Strengths

  1. Functional approach: Heavy use of functional patterns makes rules predictable and testable.
  2. Immutable-by-default: Rules don't mutate input (except for explicit assignments).
  3. Composable: Rules can be nested and combined flexibly.

Areas for Improvement

  1. Error handling strategy: Inconsistent error handling between UserError and system errors.
  2. Input validation: Validation happens at boundaries but not consistently throughout.
  3. Resource limits: No built-in limits on rule complexity or execution time.

Remediation Roadmap

Immediate (Critical - Within 1 Week)

  1. Update GitHub Actions

    • Update to actions/checkout@v4 and actions/setup-node@v4
    • Add Node.js 18, 20, 22 to test matrix
  2. Update core dependencies

    • Jest, ts-jest to latest versions
    • TypeScript to 5.x
    • ESLint to 9.x
  3. Add prototype pollution deep validation

    • Implement recursive key checking
    • Add tests for nested prototype pollution attempts

Short-Term (High - Within 1 Month)

  1. Expression parser hardening

    • Add expression complexity limits
    • Implement execution timeout
    • Add function whitelist mechanism
  2. Rule structure validation

    • Add validateRule() function
    • Implement max nesting depth
    • Add comprehensive rule schema validation
  3. Improve error handling

    • Restore stack traces for non-UserError exceptions
    • Add error cause tracking
    • Implement structured error logging

Medium-Term (Architectural - Within Quarter)

  1. TypeScript strictness

    • Remove all @ts-expect-error comments
    • Eliminate any types
    • Add comprehensive type tests
  2. Performance optimization

    • Add memoization for pure functions
    • Benchmark and document performance characteristics
    • Add performance regression tests
  3. Documentation improvements

    • Security considerations section
    • Performance guidelines
    • Error handling patterns

Medium & Low Findings Summary

ID Severity Category Description
MEDIUM-01 Medium Code Quality Inadequate Error Handling
MEDIUM-02 Medium Code Quality Inconsistent TypeScript Strictness
MEDIUM-03 Medium Security Reserved Key Validation Bypass
LOW-01 Low Performance Missing Memoization
LOW-02 Low Documentation Documentation Gaps

Security Checklist

  • Prototype pollution protection (deep validation)
  • Expression complexity limits
  • Execution timeout mechanism
  • Input validation for rule structures
  • Dependency security updates
  • CI/CD pipeline security updates
  • Error handling improvements
  • Reserved key protection enhancement

Appendix: File Inventory

Source Files (10 TypeScript files)

src/
β”œβ”€β”€ index.ts              # Main rule engine (560 lines)
β”œβ”€β”€ index.test.ts         # Main test file (526 lines)
β”œβ”€β”€ arrays.test.ts        # Array method tests (127 lines)
β”œβ”€β”€ types.ts              # Type exports (1 line)
β”œβ”€β”€ expression-language/
β”‚   β”œβ”€β”€ index.ts          # Expression parser config (629 lines)
β”‚   └── utils.ts          # Expression utilities (213 lines)
└── utils/
    β”œβ”€β”€ errors.ts         # UserError class (15 lines)
    β”œβ”€β”€ utils.ts          # Type utilities (43 lines)
    β”œβ”€β”€ performance.ts    # Performance wrapper
    └── mockDateHelper.ts # Test utility

Configuration Files

  • package.json - Dependencies and scripts
  • tsconfig.json - TypeScript configuration
  • tsup.config.ts - Build configuration
  • .eslintrc.js - ESLint configuration
  • .prettierrc - Code formatting
  • jest.config.ts - Test configuration
  • .github/workflows/test.yml - CI/CD pipeline

Conclusion

The rules-machine library is a solid, well-architected rules engine with good foundations. The primary concerns are:

  1. Outdated dependencies and CI/CD - Critical security and compatibility risk
  2. Security hardening - Needs deeper prototype pollution protection and expression sandboxing
  3. TypeScript rigor - Some technical debt in type definitions

Addressing the critical findings should be prioritized, followed by security hardening. The codebase architecture is sound and supports incremental improvements without requiring major refactoring.


Generated: April 6, 2026 Next Review: Recommend quarterly security audits after remediation