{"record":{"id":"334a4b3519f67f46","repo":"FlowiseAI/Flowise","slug":"disallowed-typeorm-datasource-option-key","errorCode":null,"errorMessage":"Disallowed TypeORM DataSource option: ${key}","messagePattern":"Disallowed TypeORM DataSource option: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/components/src/sanitizeDataSourceOptions.ts","lineNumber":23,"sourceCode":"\n/** Connection options that must be set by the node, not via additionalConfig. */\nconst RESERVED_CONNECTION_KEYS = ['database', 'type', 'url', 'host', 'port', 'username', 'password'] as const\n\nexport type BlockedDataSourceKey = (typeof BLOCKED_DATASOURCE_KEYS)[number]\nexport type ReservedConnectionKey = (typeof RESERVED_CONNECTION_KEYS)[number]\n\n/**\n * Rejects user-supplied TypeORM DataSource options that can lead to arbitrary code execution\n * when passed to `new DataSource(options).initialize()`.\n */\nexport function sanitizeDataSourceOptions(config: ICommonObject): ICommonObject {\n    if (!config || typeof config !== 'object' || Array.isArray(config)) {\n        return {}\n    }\n\n    for (const key of BLOCKED_DATASOURCE_KEYS) {\n        if (key in config) {\n            throw new Error(`Disallowed TypeORM DataSource option: ${key}`)\n        }\n    }\n\n    return { ...config }\n}\n\n/**\n * Rejects user-supplied connection fields that must not override node-controlled settings.\n */\nexport function rejectReservedDataSourceKeys(config: ICommonObject): void {\n    if (!config || typeof config !== 'object' || Array.isArray(config)) {\n        return\n    }\n\n    for (const key of RESERVED_CONNECTION_KEYS) {\n        if (key in config) {\n            throw new Error(`Disallowed TypeORM DataSource option: ${key}`)\n        }","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/src/sanitizeDataSourceOptions.ts#L5-L41","documentation":"sanitizeDataSourceOptions rejects any config containing a key in BLOCKED_DATASOURCE_KEYS = ['entities','subscribers','migrations','extra']. These TypeORM DataSource options accept file paths that TypeORM dynamically imports/executes during DataSource.initialize(), so accepting them from user input is an arbitrary-code-execution vector. The guard throws the moment any blocked key is present, before the config reaches TypeORM.","triggerScenarios":"User-supplied additionalOptions/credentialOptions JSON includes 'entities', 'subscribers', 'migrations', or 'extra' (e.g. 'entities': ['./*.entity.js']).","commonSituations":"Pasting a TypeORM tutorial connection snippet that lists entities/migrations; migrating from a standalone TypeORM app config into Flowise's additionalOptions field; attempting to point TypeORM at custom entity files.","solutions":["Remove 'entities', 'subscribers', 'migrations', and 'extra' from the user-supplied config.","If entity/migration loading is genuinely required, it must be controlled by the node implementation, never passed through user input.","Validate config keys against an allowlist before calling sanitizeDataSourceOptions to fail earlier with a clearer message."],"exampleFix":"// before: user config triggers ACE-prevention guard\nsanitizeDataSourceOptions({ type: 'postgres', entities: ['src/entity/*.js'] }) // throws\n\n// after: drop blocked keys; entities are node-controlled\nsanitizeDataSourceOptions({ type: 'postgres', schema: 'public' })","handlingStrategy":"validation","validationCode":"const BLOCKED = ['entities', 'subscribers', 'migrations', 'extra'] as const\n\nfunction stripBlockedDataSourceKeys<T extends Record<string, unknown>>(cfg: T): T {\n  const out: any = { ...cfg }\n  for (const k of BLOCKED) delete out[k]\n  return out\n}","typeGuard":"const hasNoBlockedDataSourceKeys = (cfg: unknown): boolean =>\n  !!cfg && typeof cfg === 'object' &&\n  !['entities', 'subscribers', 'migrations', 'extra'].some((k) => k in (cfg as object))","tryCatchPattern":"try {\n  return sanitizeDataSourceOptions(userConfig)\n} catch (e) {\n  throw new Error(`Rejected user datasource config: ${(e as Error).message}. Remove entities/subscribers/migrations/extra.`, { cause: e })\n}","preventionTips":["Never accept entities/subscribers/migrations/extra from end users; these are ACE vectors via TypeORM file loading.","Drive entity/migration loading from node-controlled code only.","Allowlist additionalOption keys at the API boundary."],"tags":["security","typeorm","validation","code-execution","rce"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}