feat(inventory): add security hardening for prototype pollution and DoS
Created comprehensive security layer to protect against malicious input and resource exhaustion attacks. New security.js module: - sanitizeLocationName(): Blocks __proto__, constructor, toString, etc. - sanitizeItemName(): Enforces max length (500 chars) - validateStoredInventory(): Validates entire stored object structure - MAX_ITEMS_PER_SECTION: Limit of 500 items per section Protected attack vectors: 1. Prototype pollution via location names - Blocked: "__proto__", "constructor", "prototype", etc. - Alert shown to user if attempted 2. DoS via extremely long names - Location names: max 200 chars (truncated with warning) - Item names: max 500 chars (truncated with warning) 3. DoS via massive item lists - Max 500 items per section (truncated with warning) Integration: - itemParser.js: Uses sanitizeItemName() and enforces max items - inventoryActions.js: Validates all user input before saving - Manual location creation: blocked dangerous names - Manual item addition: length limits enforced Security best practices (2025): - No regex DoS vulnerabilities (character-by-character parsing) - Explicit hasOwnProperty checks to avoid inherited properties - Console warnings for all security events (auditing) - Graceful degradation (truncate, don't crash) - Defense in depth (validation at multiple layers) This protects against both malicious actors and accidental abuse.
This commit is contained in:
+19
-3
@@ -3,6 +3,8 @@
|
||||
* Utilities for parsing item strings into arrays and vice versa
|
||||
*/
|
||||
|
||||
import { sanitizeItemName, MAX_ITEMS_PER_SECTION } from './security.js';
|
||||
|
||||
/**
|
||||
* Parses item strings from AI responses into clean arrays.
|
||||
* Handles numerous AI formatting quirks and edge cases.
|
||||
@@ -124,7 +126,7 @@ export function parseItems(itemString) {
|
||||
processed = processed.replace(/\s+/g, ' ');
|
||||
|
||||
// STEP 6: Smart comma splitting (only split on commas OUTSIDE parentheses)
|
||||
// Also handles list markers and quotes per-item
|
||||
// Also handles list markers, quotes, and security validation per-item
|
||||
const items = [];
|
||||
let currentItem = '';
|
||||
parenDepth = 0;
|
||||
@@ -147,7 +149,17 @@ export function parseItems(itemString) {
|
||||
// Comma outside parentheses - this is a separator
|
||||
const cleaned = cleanSingleItem(currentItem);
|
||||
if (cleaned) {
|
||||
items.push(cleaned);
|
||||
// Security check: validate and sanitize item name
|
||||
const sanitized = sanitizeItemName(cleaned);
|
||||
if (sanitized) {
|
||||
items.push(sanitized);
|
||||
}
|
||||
|
||||
// DoS protection: enforce max items limit
|
||||
if (items.length >= MAX_ITEMS_PER_SECTION) {
|
||||
console.warn(`[RPG Companion] Reached max items limit (${MAX_ITEMS_PER_SECTION}), truncating list`);
|
||||
return items;
|
||||
}
|
||||
}
|
||||
currentItem = ''; // Start new item
|
||||
} else {
|
||||
@@ -158,7 +170,11 @@ export function parseItems(itemString) {
|
||||
// Don't forget the last item
|
||||
const cleaned = cleanSingleItem(currentItem);
|
||||
if (cleaned) {
|
||||
items.push(cleaned);
|
||||
// Security check: validate and sanitize item name
|
||||
const sanitized = sanitizeItemName(cleaned);
|
||||
if (sanitized) {
|
||||
items.push(sanitized);
|
||||
}
|
||||
}
|
||||
|
||||
// Warn if parentheses were unmatched
|
||||
|
||||
Reference in New Issue
Block a user