T09 · Insecure Skill Coding Practices
- Location
src/content-analyzer.js:258- Finding
Regular Expression Injection Enables Event-Loop Denial of Service
- Content
View full analysis
Vulnerability Details
File Location:
src/content-analyzer.js, lines 258-264
Vulnerability Type: Regular expression injection and denial of service
Risk Level: MediumVulnerable Code
javascript for (const keyword of keywords) { const keywordLower = keyword.toLowerCase(); const occurrences = (contentLower.match(new RegExp(keywordLower, 'g')) || []).length; const density = (occurrences / this._countWords(content)) * 100;Technical Analysis
The application inserts an attacker-controlled keyword directly into the
RegExpconstructor without escaping regular-expression metacharacters. The keyword is therefore interpreted as executable regular-expression syntax rather than as a literal search term.An invalid expression such as
[causes the constructor to throw a syntax error. More importantly, a pattern containing nested or ambiguous quantifiers, such as(a+)+$, can cause catastrophic backtracking when evaluated against suitably crafted content. Because Node.js evaluates this regular expression synchronously on the main event loop, a computationally expensive match can prevent the process from servicing other requests.Both the content and keyword arrays are exposed through the exported
optimizeContent(content, keywords)API and theoptimize_contentaction handled byindex.js. No input-size limits, keyword-count limits, regular-expression escaping, or execution timeout protects this operation.Attack Path
- An attacker submits an
optimize_contentrequest with a crafted keyword such as(a+)+$. - The attacker supplies content containing a long sequence of
acharacters followed by a nonmatching character, such asaaaaaaaa...!. index.jsforwards the content and keyword array toSEOEngine.optimizeContent().- The content analyzer converts the attacker-controlled keyword into a regular expression at
src/content-analyzer.js:263. - Matching the expression ...[truncated 939 chars]
- An attacker submits an
- Remediation
View remediation
Remediation Suggestions
Treat keywords as literal text rather than regular-expression source. Escape all regular-expression metacharacters before constructing a
RegExp:javascript function escapeRegExp(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } for (const keyword of keywords) { if (typeof keyword !== 'string' || keyword.length === 0) { continue; } const escapedKeyword = escapeRegExp(keyword.toLowerCase()); const occurrences = (contentLower.match(new RegExp(escapedKeyword, 'g')) || []).length; const density = (occurrences / Math.max(this._countWords(content), 1)) * 100; }Prefer a literal string-counting implementation using
indexOf()when regular-expression behavior is unnecessary. This eliminates regular-expression injection entirely.Apply additional defense-in-depth controls:
- Validate that
contentis a string andkeywordsis an array of strings. - Enforce maximum lengths for content and each keyword.
- Enforce a maximum number of keywords per request.
- Reject empty or excessively complex input before analysis.
- Apply request-level rate limits where the package is exposed through an API.
- Add regression tests using malformed patterns such as
[and pathological patterns such as(a+)+$, verifying that they are processed as literal text. - For high-volume services, isolate CPU-intensive analysis in worker threads or separate processes with execution deadlines.
- Validate that
