Skip to content

feat!: limit usage of the eval function#736

Merged
tbouffard merged 1 commit intomainfrom
feat/limit_usage_of_eval
Mar 27, 2025
Merged

feat!: limit usage of the eval function#736
tbouffard merged 1 commit intomainfrom
feat/limit_usage_of_eval

Conversation

@tbouffard
Copy link
Member

@tbouffard tbouffard commented Mar 27, 2025

StylesheetCodec no longer call the function by default.
The eslint configuration now includes a new rule that prevents new calls to the function.

Introduce an internal function for indirection of the eval function. This change generates fewer warnings when using bundlers such as Rollup.
Be aware that this is a temporary workaround, not a final solution.

BREAKING CHANGES: StylesheetCodec.allowEval is now set to false by default to prevent unwanted use of the eval function, as it carries a possible security risk.

Notes

Covers #722

eslint rule: https://eslint.org/docs/latest/rules/no-eval

Summary by CodeRabbit

  • Chores
    • Introduced a new linting rule to prevent unsafe code evaluation practices.
  • Breaking Changes
    • Updated default configurations for dynamic evaluation in style processing to enhance security.
  • Refactor
    • Replaced legacy direct code execution calls with a secure alternative across various components.

`StylesheetCodec` no longer call the function by default.
The eslint configuration now includes a new rule that prevents new calls to the function.

Introduce an internal function for indirection of the `eval` function. This change generates fewer warnings when using bundlers such as Rollup.
Be aware that this is a temporary workaround, not a final solution.

BREAKING CHANGES: `StylesheetCodec.allowEval` is now set to `false` by default to prevent unwanted use of the eval function,
as it carries a possible security risk.
@tbouffard tbouffard added the enhancement New feature or request label Mar 27, 2025
@coderabbitai
Copy link

coderabbitai bot commented Mar 27, 2025

Walkthrough

This pull request enforces stricter security measures regarding the use of eval. A new ESLint rule ("no-eval": "error") prevents its usage in the codebase, and all instances of eval across several modules have been replaced with a custom utility function, doEval. Additionally, the default setting for StylesheetCodec.allowEval has been changed from true to false, as noted in the changelog, further mitigating risks associated with dynamic code evaluation.

Changes

File(s) Change Summary
.eslintrc.json Added ESLint rule "no-eval": "error" to disallow usage of eval.
CHANGELOG.md Added Breaking Changes section updating StylesheetCodec.allowEval default from true to false.
packages/core/src/internal/utils.ts Introduced new utility function doEval(expression: string) that encapsulates the use of eval.
packages/core/src/editor/EditorPopupMenu.ts, .../serialization/ObjectCodec.ts, .../codecs/editor/EditorToolbarCodec.ts, .../view/GraphView.ts, .../geometry/node/StencilShape.ts Replaced all native eval calls with the safer doEval function in various methods.
packages/core/src/serialization/codecs/StylesheetCodec.ts Replaced eval with doEval for text evaluation and updated the static property allowEval default from true to false.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant doEval
    participant JS_Eval
    Caller->>doEval: Call doEval(expression)
    doEval->>JS_Eval: Evaluate expression using native eval
    JS_Eval-->>doEval: Return evaluation result
    doEval-->>Caller: Return result
Loading

Possibly related issues

Possibly related PRs

Suggested labels

documentation

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 27, 2025

Quality Gate Passed Quality Gate passed

Issues
1 New issue
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

@tbouffard tbouffard marked this pull request as ready for review March 27, 2025 12:32
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: 0

🧹 Nitpick comments (1)
packages/core/src/internal/utils.ts (1)

17-23: Good centralization of eval usage, but consider additional safeguards

Centralizing eval in a single utility function is a good approach that makes it easier to audit and control its usage. The @internal marker and comments clearly indicate the purpose.

However, the function still inherits all security risks associated with eval without additional safeguards.

Consider enhancing this function in the future with:

  • Input validation to restrict what expressions can be evaluated
  • A more detailed comment documenting safe usage patterns
  • Potentially adding a sandbox or other security measures
 /**
  * @internal
  */
 export const doEval = (expression: string): any => {
+  // TODO: Add validation to restrict what expressions can be evaluated
+  // For security best practices, this function should:
+  // 1. Validate input expressions against a safe pattern
+  // 2. Consider using more secure alternatives like JSON.parse where possible
+  // 3. Only be used for trusted inputs with no user-controlled data
   // eslint-disable-next-line no-eval -- valid here as we want this function to be the only place in the codebase that uses eval
   return eval(expression);
 };
🧰 Tools
🪛 Biome (1.9.4)

[error] 22-22: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6acaeff and 295cbc6.

📒 Files selected for processing (9)
  • .eslintrc.json (1 hunks)
  • CHANGELOG.md (1 hunks)
  • packages/core/src/editor/EditorPopupMenu.ts (3 hunks)
  • packages/core/src/internal/utils.ts (1 hunks)
  • packages/core/src/serialization/ObjectCodec.ts (2 hunks)
  • packages/core/src/serialization/codecs/StylesheetCodec.ts (3 hunks)
  • packages/core/src/serialization/codecs/editor/EditorToolbarCodec.ts (3 hunks)
  • packages/core/src/view/GraphView.ts (3 hunks)
  • packages/core/src/view/geometry/node/StencilShape.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
packages/core/src/editor/EditorPopupMenu.ts (1)
Learnt from: tbouffard
PR: maxGraph/maxGraph#726
File: packages/core/src/editor/EditorPopupMenu.ts:197-197
Timestamp: 2025-03-27T09:34:54.875Z
Learning: The team has decided to keep using `eval()` in EditorPopupMenu.ts as the implementation is loaded from XML configuration. Finding alternatives to `eval()` for improved security is planned for future work.
🧬 Code Definitions (5)
packages/core/src/serialization/codecs/editor/EditorToolbarCodec.ts (1)
packages/core/src/internal/utils.ts (1)
  • doEval (20-23)
packages/core/src/editor/EditorPopupMenu.ts (2)
packages/core/src/internal/utils.ts (1)
  • doEval (20-23)
packages/core/src/util/domUtils.ts (1)
  • getTextContent (88-90)
packages/core/src/serialization/ObjectCodec.ts (2)
packages/core/src/internal/utils.ts (1)
  • doEval (20-23)
packages/core/src/util/domUtils.ts (1)
  • getTextContent (88-90)
packages/core/src/serialization/codecs/StylesheetCodec.ts (1)
packages/core/src/internal/utils.ts (1)
  • doEval (20-23)
packages/core/src/view/GraphView.ts (1)
packages/core/src/internal/utils.ts (1)
  • doEval (20-23)
🪛 Biome (1.9.4)
packages/core/src/internal/utils.ts

[error] 22-22: eval() exposes to security risks and performance issues.

See the MDN web docs for more details.
Refactor the code so that it doesn't need to call eval().

(lint/security/noGlobalEval)

🔇 Additional comments (18)
CHANGELOG.md (1)

12-13: Well-documented breaking change

The addition of this breaking change information is clear and helpful, providing users with an understanding of both the change and the security rationale behind it.

.eslintrc.json (1)

36-37: Good addition of security-enhancing lint rule

Adding the no-eval rule as an error is an excellent security practice that aligns with industry standards. This enforces the PR's goal of limiting eval usage across the codebase.

packages/core/src/serialization/ObjectCodec.ts (2)

27-27: Good import of centralized eval function

Importing the doEval function from the internal utils module aligns with the security goal of centralizing and controlling eval usage.


823-825: Good replacement of direct eval with centralized function

Replacing the direct call to eval with the centralized doEval function maintains the existing functionality while improving code organization and security control. The conditional check on ObjectCodec.allowEval adds an extra layer of security by ensuring evaluation only happens when explicitly enabled.

packages/core/src/serialization/codecs/editor/EditorToolbarCodec.ts (3)

27-27: Improved security through centralized evaluation.

Added import of doEval function to replace direct eval usage, aligning with the PR objective to limit eval usage.


161-161: Replaced direct eval with safer controlled evaluation.

The change ensures evaluation only happens when explicitly allowed and uses the centralized doEval function instead of direct eval.


175-175: Improved security by replacing direct eval with controlled evaluation.

Using doEval centralizes the evaluation logic and allows for better security control and monitoring.

packages/core/src/view/geometry/node/StencilShape.ts (2)

36-36: Added safer evaluation function import.

The doEval function import supports the PR's security objectives by providing a centralized place for evaluation.


197-197: Enhanced security by replacing direct eval with controlled evaluation.

Changing from direct eval to doEval helps mitigate security risks and aligns with the ESLint rule added in this PR to prevent direct eval usage.

packages/core/src/editor/EditorPopupMenu.ts (3)

27-27: Added import for secure evaluation function.

The added import supports the PR's objective to limit and control the use of eval.


321-321: Enhanced security by replacing direct eval with controlled function.

The change maintains compatibility with the XML-based configuration approach while improving security.


198-198:

Details

✅ Verification successful

Replaced direct eval with controlled evaluation.

This change improves security while maintaining the functionality required for XML-based configuration.


🏁 Script executed:

#!/bin/bash
# Check if there are any remaining direct eval calls in this file
rg -i "eval\(" packages/core/src/editor/EditorPopupMenu.ts

Length of output: 202


Confirmed use of controlled evaluation in EditorPopupMenu.ts

  • The verification confirms that there are no direct invocations of eval()—both instances (one using item and one using condNode) make use of the wrapper function doEval().
  • This controlled evaluation aligns with our current approach for XML-based configuration, as per the team's decision.
packages/core/src/serialization/codecs/StylesheetCodec.ts (3)

25-25: Added import for secure evaluation function.

This import supports the PR's security objectives by centralizing evaluation logic.


166-166: Replaced direct eval with controlled evaluation function.

Using doEval instead of direct eval enhances security while maintaining functionality for those who explicitly opt-in.


45-47:

Details

✅ Verification successful

BREAKING CHANGE: allowEval now defaults to false.

This is an important security improvement that matches the PR objectives. By defaulting to false, the system now requires explicit opt-in for evaluation of potentially unsafe code.


🌐 Web query:

What are the security risks of using eval in JavaScript?

💡 Result:

The eval() function in JavaScript allows dynamic code execution from strings, but introduces significant security risks that require careful handling. Its ability to execute arbitrary code makes it vulnerable to exploitation if inputs aren't properly controlled. Below are the primary security concerns and their implications.

Code Injection Attacks
eval() can execute malicious code if inputs originate from untrusted sources like user inputs, cookies, or API responses. Attackers may inject commands to steal data, hijack sessions, or deploy malware[1][3]. For example, a text field using eval() on user input could enable Cross-Site Scripting (XSS) attacks if exploited[3][5].

Scope Pollution
Evaluated code runs in the current scope, allowing access to and modification of global variables. This exposes sensitive data and creates unpredictable side effects, such as overwriting critical functions or variables[1][2]. For instance, a malicious script via eval() could redefine authentication logic or leak environment variables[2][3].

Performance and Maintenance Issues

  • Slow Execution: eval() parses and interprets code at runtime, bypassing JavaScript engine optimizations and slowing down applications[1][2][4].
  • Debugging Complexity: Errors in dynamically evaluated code lack clear stack traces, complicating troubleshooting[1][4].

Unintended Code Execution
Even "sanitized" inputs can exploit eval(). For example, modifying client-side data attributes (e.g., data-* attributes) via browser tools lets attackers inject arbitrary code if eval() processes those values[5].

Safer Alternatives

  • JSON Parsing: Use JSON.parse() instead of eval() for data serialization[2].
  • Function Constructor: Create scoped functions via new Function() to limit variable access[4].
  • Static Analysis Tools: Detect insecure eval() usage with tools like Codiga, which flags risky patterns in codebases[1].

While eval() has niche uses, prioritizing alternatives and rigorously validating inputs minimizes exposure to code injection, data breaches, and system compromises[1][2][3]. Always restrict eval() to controlled, non-user-facing contexts when unavoidable.

Citations:


Security Enhancement Notice: allowEval now defaults to false

The updated default value effectively mitigates the significant security risks associated with eval(), such as code injection, scope pollution, and performance issues. By requiring an explicit opt-in for execution of dynamic code, this breaking change aligns with our security objectives and reduces the attack surface.

  • File: packages/core/src/serialization/codecs/StylesheetCodec.ts (Lines 45-47)
  • Change Summary:
    • The property is now defined as:
      /**
       * @default false
       */
      static allowEval = false;
    • This change prevents inadvertent execution of potentially unsafe code unless explicitly permitted by the developer.
packages/core/src/view/GraphView.ts (3)

49-49: Good addition of the doEval import

This import adds the centralized evaluation utility that replaces direct eval calls, aligning with the PR's security objectives.


1330-1332: Security improvement by replacing eval with doEval

Replacing direct eval(edgeStyle) with doEval(edgeStyle) centralizes dynamic code evaluation to a single location in the codebase, making it easier to track and secure. This change is guarded by the isAllowEval() check which is now false by default.


1597-1599: Security improvement by replacing eval with doEval

Replacing direct eval(perimeter) with doEval(perimeter) follows the same security pattern applied throughout the codebase. This centralized approach improves security and maintainability.

@tbouffard tbouffard merged commit 4dec295 into main Mar 27, 2025
7 checks passed
@tbouffard tbouffard deleted the feat/limit_usage_of_eval branch March 27, 2025 12:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant