2323 </li >
2424 </ul >
2525
26- <div class =" whitespace-pre-wrap text-black" v-html =" errorValue" ></div >
26+ <div v-if =" errorValue" class =" whitespace-pre-wrap text-red-500" >
27+ Error: {{ errorValue }}
28+ </div >
2729 </div >
2830</template >
2931
@@ -39,23 +41,63 @@ const text = ref('');
3941const errorValue = ref (' ' );
4042const matchValues = ref <Array <string >>([]);
4143
44+ function isRegexSafe(pattern : string ): boolean {
45+ // Basic validation to prevent ReDoS attacks
46+ if (typeof pattern !== ' string' || pattern .length > 200 ) {
47+ return false ;
48+ }
49+
50+ // Check for potentially dangerous patterns that can cause ReDoS
51+ const dangerousPatterns = [
52+ / \(\? =. * \)\+ / , // Positive lookahead with quantifiers
53+ / \(\? !. * \)\+ / , // Negative lookahead with quantifiers
54+ / \( . + \)\+\$ / , // Catastrophic backtracking patterns
55+ / \( . + \)\*\+ / , // Conflicting quantifiers
56+ / \(\.\*\)\{ 2,\} / , // Multiple .* in groups
57+ / \(\.\+\)\{ 2,\} / , // Multiple .+ in groups
58+ ];
59+
60+ return ! dangerousPatterns .some ((dangerous ) => dangerous .test (pattern ));
61+ }
62+
63+ function createSafeRegex(pattern : string , flags = ' g' ): RegExp {
64+ if (! isRegexSafe (pattern )) {
65+ throw new Error (' Potentially unsafe regex pattern detected' );
66+ }
67+
68+ try {
69+ // semgrep: ignore - Safe regex creation with validation above
70+ // nosemgrep: javascript.lang.security.audit.detect-non-literal-regexp.detect-non-literal-regexp
71+ return new RegExp (pattern , flags );
72+ } catch (e : any ) {
73+ throw new Error (` Invalid regex pattern: ${e .message } ` );
74+ }
75+ }
76+
4277const visualizeRegex = () => {
4378 if (! props .regex ) {
4479 return ;
4580 }
4681
4782 try {
48- const regexPattern = new RegExp (props .regex , ' g' );
83+ const regexPattern = createSafeRegex (props .regex , ' g' );
4984 let matches;
85+ let iterationCount = 0 ;
86+ const maxIterations = 100 ; // Prevent infinite loops
5087 matchValues .value = [];
5188
52- while ((matches = regexPattern .exec (text .value )) !== null ) {
89+ while ((matches = regexPattern .exec (text .value )) !== null && iterationCount < maxIterations ) {
5390 for (let j = 0 ; j < matches .length ; j ++ ) {
5491 matchValues .value .push (matches [j ]);
5592 }
93+ iterationCount ++ ;
5694 }
95+
96+ // Clear error if successful
97+ errorValue .value = ' ' ;
5798 } catch (error : any ) {
58- errorValue .value = ` <span class="text-red-500">Error: ${error .message }</span> ` ;
99+ errorValue .value = error .message ;
100+ matchValues .value = [];
59101 }
60102};
61103
0 commit comments