{"record":{"id":"af5ba8aff04902f9","repo":"apify/crawlee","slug":"segment-is-not-allowed-because-it-would-resol","errorCode":null,"errorMessage":"\"${segment}\" is not allowed because it would resolve outside of the storage directory. Storage names and record keys must not contain path traversal segments (\"..\") or absolute paths.","messagePattern":"\"(.+?)\" is not allowed because it would resolve outside of the storage directory\\. Storage names and record keys must not contain path traversal segments \\(\"\\.\\.\"\\) or absolute paths\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/memory-storage/utils.ts","lineNumber":16,"sourceCode":"import { createHash } from 'node:crypto';\nimport { resolve, sep } from 'node:path';\n\nimport { REQUEST_ID_LENGTH } from './consts.js';\n\n/**\n * Resolves `segment` against `baseDirectory` and ensures the result stays within `baseDirectory`.\n * Storage names and record keys are used as filesystem path components, so a value containing `..`\n * or an absolute path could otherwise escape the intended directory.\n */\nexport function resolveWithinDirectory(baseDirectory: string, segment: string): string {\n    const base = resolve(baseDirectory);\n    const resolved = resolve(base, segment);\n\n    if (resolved !== base && !resolved.startsWith(`${base}${sep}`)) {\n        throw new Error(\n            `\"${segment}\" is not allowed because it would resolve outside of the storage directory. ` +\n                `Storage names and record keys must not contain path traversal segments (\"..\") or absolute paths.`,\n        );\n    }\n\n    return resolved;\n}\n\n/**\n * Removes all properties with a null value\n * from the provided object.\n */\nexport function purgeNullsFromObject<T>(object: T): T {\n    if (object && typeof object === 'object' && !Array.isArray(object)) {\n        for (const [key, value] of Object.entries(object)) {\n            if (value === null) Reflect.deleteProperty(object as Record<string, unknown>, key);\n        }\n    }","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/core/src/memory-storage/utils.ts#L1-L34","documentation":"resolveWithinDirectory joins a user-supplied name/key onto a base storage directory and verifies the result stays inside that base. This guards the memory-storage implementation against path traversal: names containing '..' or absolute paths could read/write files outside the storage directory. Any storage name, queue id, or record key that escapes the base is rejected.","triggerScenarios":"Passing a storage name or record key containing '..' (e.g. '../secrets'), an absolute path ('/etc/passwd'), or on Windows a drive-qualified path to MemoryStorage APIs such as opening a store/queue/dataset with such a name, or accessing a record whose key resolves outside the base directory.","commonSituations":"User-supplied storage names passed straight from input into MemoryStorage; keys built by string concatenation with unsanitized segments; attempting to alias one store to another path via traversal; security testing of crawlee memory storage.","solutions":["Sanitize the name/key: strip or reject '..' segments, leading '/', and drive letters before passing it.","Use only alphanumeric, dash, and underscore characters for storage names and record keys.","If nested organization is needed, create separate storages instead of encoding paths in the name.","Validate untrusted input at the boundary (e.g. a schema with a regex like /^[A-Za-z0-9_-]+$/)."],"exampleFix":"// before\nconst store = await MemoryStorage.openStore(userInput); // '../other'\n// after\nconst name = userInput.replace(/[^A-Za-z0-9_-]/g, '');\nif (!name) throw new Error('Invalid storage name');\nconst store = await MemoryStorage.openStore(name);","handlingStrategy":"validation","validationCode":"function isSafeStorageName(name) {\n  return typeof name === 'string' && /^[A-Za-z0-9_-]+$/.test(name);\n}\nif (!isSafeStorageName(userInput)) throw new Error('Invalid storage name');","typeGuard":"function isSafeStorageSegment(s: unknown): s is string {\n  return typeof s === 'string' && s.length > 0 && !s.includes('..') && !s.startsWith('/') && !s.includes('\\\\') && /^[A-Za-z0-9_-]+$/.test(s);\n}","tryCatchPattern":"try {\n  return resolveWithinDirectory(base, segment);\n} catch (err) {\n  if ((err as Error).message.includes('would resolve outside of the storage directory')) {\n    throw new ValidationError(`Unsafe storage key: ${segment}`);\n  }\n  throw err;\n}","preventionTips":["Restrict storage names/keys to [A-Za-z0-9_-].","Never pass raw user input as a storage name or record key.","Sanitize at the API boundary before any storage call.","Treat traversal attempts as security events and log them."],"tags":["path-traversal","security","memory-storage","validation"],"backgroundTag":"path-traversal-rejected","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}