{"record":{"id":"f09937a3d249ac7e","repo":"paperclipai/paperclip","slug":"plugin-sql-contains-a-disallowed-statement-or-clau","errorCode":null,"errorMessage":"Plugin SQL contains a disallowed statement or clause: ${matched.source}","messagePattern":"Plugin SQL contains a disallowed statement or clause: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/plugin-database.ts","lineNumber":186,"sourceCode":"}\n\nfunction assertNoBannedSql(statement: string): void {\n  const normalized = normaliseSql(statement);\n  const banned = [\n    /\\bcreate\\s+extension\\b/,\n    /\\bcreate\\s+(?:event\\s+)?trigger\\b/,\n    /\\bcreate\\s+(?:or\\s+replace\\s+)?function\\b/,\n    /\\bcreate\\s+language\\b/,\n    /\\bgrant\\b/,\n    /\\brevoke\\b/,\n    /\\bsecurity\\s+definer\\b/,\n    /\\bcopy\\b/,\n    /\\bcall\\b/,\n    /\\bdo\\s+(?:\\$\\$|language\\b)/,\n  ];\n  const matched = banned.find((pattern) => pattern.test(normalized));\n  if (matched) {\n    throw new Error(`Plugin SQL contains a disallowed statement or clause: ${matched.source}`);\n  }\n}\n\nexport function validatePluginMigrationStatement(\n  statement: string,\n  namespace: string,\n  coreReadTables: readonly PluginDatabaseCoreReadTable[] = [],\n): void {\n  assertIdentifier(namespace, \"namespace\");\n  assertNoBannedSql(statement);\n\n  const normalized = normaliseSql(statement);\n  if (/^\\s*(drop|truncate)\\b/.test(normalized)) {\n    throw new Error(\"Destructive plugin migrations are not allowed in Phase 1\");\n  }\n\n  if (/\\bdelete\\s+from\\b/.test(normalized)) {\n    throw new Error(\"Plugin migrations cannot delete data\");","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/server/src/services/plugin-database.ts#L168-L204","documentation":"Ban-list guard (assertNoBannedSql): the normalized plugin SQL matched one of the prohibited patterns (create extension/trigger/function/language, grant, revoke, security definer, copy, call, do-blocks). These constructs let plugins escalate privileges or execute arbitrary host-side logic; the matched regex source is embedded in the message.","triggerScenarios":"Thrown at server/src/services/plugin-database.ts:186 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Remove the disallowed statement or clause named in the message from the plugin SQL."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}