fix(security): replace new Function() with safe math expression parser#753
Conversation
Replace the dangerous new Function() constructor in evaluateMathExpression() with a recursive descent parser that safely evaluates basic arithmetic expressions. The Function constructor is a security anti-pattern that could enable arbitrary code execution if the validation regex is ever bypassed or relaxed. The new parser: - Only supports numbers, +, -, *, /, parentheses, and whitespace - Has no eval-like functionality that could execute arbitrary code - Maintains backward compatibility with existing expressions - Handles operator precedence and parentheses correctly Fixes OpenCut-app#725
|
@cyphercodes is attempting to deploy a commit to the OpenCut OSS Team on Vercel. A member of the Team first needs to authorize it. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughReplaces the use of Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/web/src/utils/math.ts (1)
150-167: Use descriptive tokenizer variable namesConsider renaming
i,str,char, andnumStrto full names (tokenIndex,trimmedInput,currentCharacter,numberLiteral) for readability and consistency.As per coding guidelines: "Never abbreviate variable and parameter names. Use
eventnote,elementnotel."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/utils/math.ts` around lines 150 - 167, Rename the terse tokenizer variables in the while-loop to descriptive names for readability: change i to tokenIndex, str to trimmedInput, char to currentCharacter, and numStr to numberLiteral throughout the tokenization block (the loop that trims input and iterates characters to build numeric literals). Update all references inside that scope (including the inner while that accumulates digits and dots) so logic and behavior remain identical.apps/web/src/utils/__tests__/math.test.ts (1)
50-55: Add malformed-decimal regression casesPlease add cases like
"1..2+3"and"12.3.4"assertingnull, so invalid numeric literals are explicitly locked down.Also applies to: 71-100
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/utils/__tests__/math.test.ts` around lines 50 - 55, Add regression tests to the decimal-number suite covering malformed numeric literals so evaluateMathExpression returns null for invalid decimals: add cases like expect(evaluateMathExpression({ input: "1..2+3" })).toBeNull() and expect(evaluateMathExpression({ input: "12.3.4" })).toBeNull(); place them alongside the existing decimal tests for "3.5+2.5" and "10.5 * 2" (also mirror similar additions in the other test block referenced around lines 71-100) to ensure invalid numeric literals are explicitly asserted as null.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/src/utils/math.ts`:
- Around line 163-171: The code currently uses Number.parseFloat on numStr which
accepts malformed tokens like "1..2"; update the numeric validation before
conversion: after building numStr in the numeric parsing loop (variable numStr
inside the tokenization logic in utils/math.ts), validate it with a strict regex
such as /^\d+(\.\d+)?$/ (ensuring at most one decimal point and at least one
digit before the dot), throw the existing Error(`Invalid number: ${numStr}`) if
it doesn't match, and then convert using Number(numStr) (or parseFloat only
after the regex check) to produce value.
---
Nitpick comments:
In `@apps/web/src/utils/__tests__/math.test.ts`:
- Around line 50-55: Add regression tests to the decimal-number suite covering
malformed numeric literals so evaluateMathExpression returns null for invalid
decimals: add cases like expect(evaluateMathExpression({ input: "1..2+3"
})).toBeNull() and expect(evaluateMathExpression({ input: "12.3.4"
})).toBeNull(); place them alongside the existing decimal tests for "3.5+2.5"
and "10.5 * 2" (also mirror similar additions in the other test block referenced
around lines 71-100) to ensure invalid numeric literals are explicitly asserted
as null.
In `@apps/web/src/utils/math.ts`:
- Around line 150-167: Rename the terse tokenizer variables in the while-loop to
descriptive names for readability: change i to tokenIndex, str to trimmedInput,
char to currentCharacter, and numStr to numberLiteral throughout the
tokenization block (the loop that trims input and iterates characters to build
numeric literals). Update all references inside that scope (including the inner
while that accumulates digits and dots) so logic and behavior remain identical.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8a2fe5e8-deb9-4a67-b741-d23e5b89a368
📒 Files selected for processing (2)
apps/web/src/utils/__tests__/math.test.tsapps/web/src/utils/math.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Summary
Fixes #725 by replacing the dangerous
new Function()constructor inevaluateMathExpression()with a safe recursive descent parser.Problem
The
evaluateMathExpressionfunction inapps/web/src/utils/math.tsusednew Function()to evaluate math expressions. While the current regex validation is reasonably tight, using the Function constructor is inherently dangerous and a recognized anti-pattern. If the validation logic is ever relaxed or refactored, this becomes a vector for arbitrary code execution.Solution
Replaced the Function constructor with a proper recursive descent parser that:
nullfor any invalid or potentially dangerous inputChanges
evaluateMathExpression()to use a safe parserTesting
All tests pass:
Security Impact
This change eliminates a potential code injection vulnerability while maintaining full backward compatibility with existing functionality.
Summary by CodeRabbit
Bug Fixes
Refactor
Tests