T09 · Insecure Skill Coding Practices
Warning
- Location
- engine/router.js:217
- Finding
- Unbounded Schedule Parameters Allow Resource-Exhaustion Denial of Service<![CDATA[ ## Vulnerability Details **File Location**: `engine/router.js:8-17`, `engine/router.js:21-31`, and `engine/router.js:217-226` **Mirrored Source Location**: `engine/router.ts:27-47` and `engine/router.ts:222-230` **Vulnerability Type**: Uncontrolled resource consumption caused by missing input validation **Risk Level**: Medium ### Vulnerable Code ```javascript // Calculate the number of phases function calculatePhaseCount(totalWeeks) { if (totalWeeks <= 4) return 1; if (totalWeeks <= 8) return 2; if (totalWeeks <= 16) return 3; return Math.ceil(totalWeeks / 4); } // Generate learning phases function generatePhases(request, totalWeeks, hoursPerWeek) { const phases = []; const phaseCount = calculatePhaseCount(totalWeeks); const weeksPerPhase = Math.ceil(totalWeeks / phaseCount); const skills = request.goal?.skills || ['Related skills']; const targetLevel = request.goal?.targetLevel || 'intermediate'; // ... for (let i = 0; i < phaseCount; i++) { const phaseWeeks = Math.min( weeksPerPhase, totalWeeks - i * weeksPerPhase ); const phaseHours = hoursPerWeek * phaseWeeks; const weeklyBreakdown = []; for (let w = 0; w < phaseWeeks; w++) { weeklyBreakdown.push({ week: i * weeksPerPhase + w + 1, focus: `Week ${w + 1}`, hours: hoursPerWeek, resources: [ { type: 'course', title: `${skills[0] || 'Skill'} course`, duration: '4 hours', format: 'interactive' }, { type: 'exercise', title: 'Practical exercises', duration: '3 hours', format: 'interactive' }, { type: 'video', title: 'Supporting video tutorial', duration: '2 hours', format: 'video' }, { type: 'article', title: 'Reference reading', duration: '1 hour', ...[truncated 4427 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Implement runtime validation at the public handler boundary before performing date calculations or allocating schedule objects. 1. Require `totalWeeks` and `hoursPerWeek` to be finite positive integers. 2. Enforce conservative upper bounds appropriate to the product. For example: - `totalWeeks`: 1 through 260 - `hoursPerWeek`: 1 through 168 3. Reject invalid input with a structured validation error instead of silently applying defaults. 4. Validate arrays such as `goal.skills` and place limits on their length and individual string sizes. 5. Apply request-body size limits, rate limits, and execution timeouts at the service boundary. 6. Keep validation in shared code so the JavaScript runtime and TypeScript source cannot diverge. Example hardening: ```javascript function requireBoundedInteger(value, name, min, max, defaultValue) { const candidate = value === undefined ? defaultValue : value; if ( typeof candidate !== 'number' || !Number.isFinite(candidate) || !Number.isInteger(candidate) || candidate < min || candidate > max ) { throw new TypeError( `${name} must be an integer between ${min} and ${max}` ); } return candidate; } async function runDecisionEngine(request) { try { if (!request || typeof request !== 'object' || Array.isArray(request)) { throw new TypeError('Request must be an object'); } const totalWeeks = requireBoundedInteger( request.goal?.timeframe?.totalWeeks, 'totalWeeks', 1, 260, 12 ); const hoursPerWeek = requireBoundedInteger( request.goal?.timeframe?.hoursPerWeek, 'hoursPerWeek', 1, 168, 10 ); const phases = generatePhases(request, totalWeeks, hoursPerWeek); // Continue constructing the response. } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Invalid learning request' }; ...[truncated 280 chars]
