T09 · Insecure Skill Coding Practices
- Location
src/question-engine-v2.js:11- Finding
Unbounded quiz session caches permit memory-exhaustion denial of service
- Content
View full analysis
({ id: q.fields["题目 ID"], answer: q.fields["正确答案"], fields: q.fields })), answers: {}, startTime: Date.now(), mode: 'batch', total: questions.length }); // 4. 缓存题目 questions.forEach(q => questionCache.set(q.fields["题目 ID"], q.fields)); ``` The attempted cleanup also uses a property that was never assigned to the session: ```javascript // 清理会话 answerSessions.delete(session.userId); ``` ### Technical Analysis Quiz requests create entries in process-global `Map` objects without a time-to-live, capacity limit, eviction policy, or periodic cleanup routine. Each `answerSessions` entry retains up to ten complete question field objects, including question text, options, answers, explanations, and other Bitable fields. Abandoned sessions are never removed. Even completed sessions are not reliably removed because the session object created by `handleQuestion` does not contain a `userId` property, but `gradeBatchAnswers` calls `answerSessions.delete(session.userId)`. This resolves to `answerSessions.delete(undefined)` rather than deleting the actual user's entry. The cache is indexed by user identity. Where an attacker can create multiple accounts, identities, or otherwise cause distinct user IDs to reach the Skill, they can force continued allocation of session objects. The separate `questionCache` can also retain every distinct question ID encountered for the lifetime of the process. ### Attack Path 1. An attacker creates or ...[truncated 1337 chars]- Remediation
View remediation
({ id: q.fields["题目 ID"], answer: q.fields["正确答案"], fields: q.fields })), answers: {}, startTime: Date.now(), mode: 'batch', total: questions.length }); // After grading: answerSessions.delete(userId); ``` 2. Enforce a short session TTL, such as 10–30 minutes, and remove expired entries both on access and through a periodic cleanup task. 3. Set hard limits for: - Maximum concurrent sessions. - Maximum sessions per account. - Maximum cached questions. - Maximum size of externally supplied Bitable fields. 4. Use an LRU or bounded TTL cache instead of unrestricted `Map` objects. 5. Rate-limit quiz creation by user, tenant, and source address where the hosting platform exposes those controls. 6. Replace an existing user's session rather than accumulating historical state, and remove state on submission, cancellation, timeout, or processing errors. 7. Add load tests that create many abandoned sessions and verify that memory consumption remains bounded. ]]>
