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:
@@ -8,6 +8,7 @@ import { saveSettings, saveChatData, updateMessageSwipeData } from '../../core/p
|
||||
import { buildInventorySummary } from '../generation/promptBuilder.js';
|
||||
import { renderInventory } from '../rendering/inventory.js';
|
||||
import { parseItems, serializeItems } from '../../utils/itemParser.js';
|
||||
import { sanitizeLocationName, sanitizeItemName } from '../../utils/security.js';
|
||||
|
||||
// Type imports
|
||||
/** @typedef {import('../../types/inventory.js').InventoryV2} InventoryV2 */
|
||||
@@ -139,9 +140,17 @@ export function saveAddItem(field, location) {
|
||||
}
|
||||
|
||||
const input = $(inputId);
|
||||
const itemName = input.val().trim();
|
||||
const rawItemName = input.val().trim();
|
||||
|
||||
if (!rawItemName) {
|
||||
hideAddItemForm(field, location);
|
||||
return;
|
||||
}
|
||||
|
||||
// Security: Validate and sanitize item name
|
||||
const itemName = sanitizeItemName(rawItemName);
|
||||
if (!itemName) {
|
||||
alert('Invalid item name.');
|
||||
hideAddItemForm(field, location);
|
||||
return;
|
||||
}
|
||||
@@ -246,9 +255,17 @@ export function hideAddLocationForm() {
|
||||
export function saveAddLocation() {
|
||||
const inventory = extensionSettings.userStats.inventory;
|
||||
const input = $('#rpg-new-location-name');
|
||||
const locationName = input.val().trim();
|
||||
const rawLocationName = input.val().trim();
|
||||
|
||||
if (!rawLocationName) {
|
||||
hideAddLocationForm();
|
||||
return;
|
||||
}
|
||||
|
||||
// Security: Validate and sanitize location name
|
||||
const locationName = sanitizeLocationName(rawLocationName);
|
||||
if (!locationName) {
|
||||
alert('Invalid location name. Avoid special names like "__proto__" or "constructor".');
|
||||
hideAddLocationForm();
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user