Reject WHERE clauses that could chain statements or hide DDL. This isn't * a full SQL parser — just a keyword/character denylist to keep the surface * area equivalent to what db-exec already allows.
(where: string)
| 107 | * a full SQL parser — just a keyword/character denylist to keep the surface |
| 108 | * area equivalent to what db-exec already allows. */ |
| 109 | function validateWhere(where: string): void { |
| 110 | if (where.includes(";")) { |
| 111 | fail("--where must not contain ';' (no statement chaining)"); |
| 112 | } |
| 113 | // Strip inline strings before keyword scanning so "WHERE name = 'DROP TABLE'" |
| 114 | // doesn't trip the denylist. |
| 115 | const stripped = where |
| 116 | .replace(/'(?:''|[^'])*'/g, "''") |
| 117 | .replace(/"(?:""|[^"])*"/g, '""') |
| 118 | .toUpperCase(); |
| 119 | |
| 120 | const blocked = [ |
| 121 | " INSERT ", |
| 122 | " UPDATE ", |
| 123 | " DELETE ", |
| 124 | " DROP ", |
| 125 | " ALTER ", |
| 126 | " CREATE ", |
| 127 | " ATTACH ", |
| 128 | " DETACH ", |
| 129 | " PRAGMA ", |
| 130 | " VACUUM ", |
| 131 | "--", |
| 132 | "/*", |
| 133 | ]; |
| 134 | const padded = " " + stripped + " "; |
| 135 | for (const kw of blocked) { |
| 136 | if (padded.includes(kw)) { |
| 137 | fail(`--where must not contain "${kw.trim()}"`); |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | function parseEdits(parsed: Record<string, string>): TextEdit[] { |
| 143 | let edits: TextEdit[]; |