{"record":{"id":"c7220638e5765e6a","repo":"marmelab/react-admin","slug":"invalid-resource-key-resource","errorCode":null,"errorMessage":"Invalid resource key: ${resource}","messagePattern":"Invalid resource key: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/ra-data-local-forage/src/index.ts","lineNumber":280,"sourceCode":"            const indexes = params.ids.map((id: any) => {\n                if (!data) {\n                    throw new Error('The dataProvider is not initialized.');\n                }\n                return data[resource].findIndex(\n                    (record: any) => record.id === id\n                );\n            });\n            pullAt(data[resource], indexes);\n            updateLocalForage(resource);\n            return baseDataProvider.deleteMany(resource, params);\n        },\n    };\n};\n\nconst checkResource = resource => {\n    if (['__proto__', 'constructor', 'prototype'].includes(resource)) {\n        // protection against prototype pollution\n        throw new Error(`Invalid resource key: ${resource}`);\n    }\n};\n\nexport interface LocalForageDataProviderParams {\n    defaultData?: any;\n    prefixLocalForageKey?: string;\n    loggingEnabled?: boolean;\n}\n","sourceCodeStart":262,"sourceCodeEnd":289,"githubUrl":"https://github.com/marmelab/react-admin/blob/051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0/packages/ra-data-local-forage/src/index.ts#L262-L289","documentation":"checkResource() blocks resource names that could enable prototype pollution: `__proto__`, `constructor`, and `prototype`. Because the provider writes to `data[resource]` and persists to localForage keys built from the resource name, a malicious or buggy resource string with these values could corrupt Object prototypes. Any write method (update, updateMany, create, delete, deleteMany) throws this before doing anything else.","triggerScenarios":"Calling any mutating dataProvider method with resource set to `__proto__`, `constructor`, or `prototype` — typically from dynamic route parameters (e.g. /admin/__proto__/edit), user-controlled refs, or misconfigured resources derived from API input.","commonSituations":"Apps that build resource names from URL segments or remote config without validation; security scanners probing for prototype-pollution sinks; typos in resource definitions are NOT caught here (only the three dangerous keys).","solutions":["Audit where resource strings originate; never pass raw URL/URLSearchParams values as the resource.","Validate resources against an allowlist of known resource names before calling dataProvider methods.","Sanitize dynamic routes so `__proto__`/`constructor`/`prototype` segments never reach the dataProvider.","Keep ra-data-local-forage updated so the pollution guard stays in place."],"exampleFix":"// before: resource straight from URL\nconst { resource } = useParams();\nawait dataProvider.update(resource as string, params);\n\n// after: allowlist check\nconst allowed = ['posts', 'comments'];\nif (!allowed.includes(resource)) throw new Error('Unknown resource');\nawait dataProvider.update(resource as string, params);","handlingStrategy":"validation","validationCode":"const RESOURCE_ALLOWLIST = new Set(['posts', 'comments', 'tags']);\nexport function assertSafeResource(resource: string): void {\n  if (!RESOURCE_ALLOWLIST.has(resource)) {\n    throw new Error(`Unknown resource: ${resource}`);\n  }\n  if (['__proto__', 'constructor', 'prototype'].includes(resource)) {\n    throw new Error(`Invalid resource key: ${resource}`);\n  }\n}\n// call before every dataProvider invocation\nassertSafeResource(resource);","typeGuard":"function isSafeResource(r: string): boolean {\n  return !['__proto__', 'constructor', 'prototype'].includes(r);\n}","tryCatchPattern":"try {\n  await dataProvider.update(resource, params);\n} catch (e) {\n  if (e.message.startsWith('Invalid resource key')) {\n    notify('Invalid resource — refusing to persist data');\n    return; // never retry; this indicates hostile/malformed input\n  }\n  throw e;\n}","preventionTips":["Never derive resource names from unvalidated URL segments or API input","Use a static allowlist of resources and validate before any dataProvider call","Sanitize dynamic admin routes so dangerous keys can't reach the provider","Add a unit test asserting checkResource rejects __proto__/constructor/prototype"],"tags":["security","prototype-pollution","validation","react-admin"],"backgroundTag":"prototype-pollution-resource-key","analyzedSha":"051f511bb0afb5ea565c2d3728bf4dab0a6fa5e0","analyzedAt":"2026-08-30T02:28:14.926Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}