Skip to content

Commit 782db58

Browse files
Copilothotlong
andcommitted
fix: Address code review feedback
- Fix SQL injection risk in SQLite PRAGMA queries by sanitizing table names - Use null coalescing operator for cleaner default value check - Import utility function at top level instead of dynamic import - Add input sanitization for table names in introspection Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 7575d28 commit 782db58

3 files changed

Lines changed: 11 additions & 6 deletions

File tree

packages/drivers/sql/src/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,10 @@ export class SqlDriver implements Driver {
638638
});
639639
}
640640
} else if (this.config.client === 'sqlite3') {
641-
const result = await this.knex.raw(`PRAGMA foreign_key_list(${tableName})`);
641+
// SQLite PRAGMA doesn't support parameter binding, so we need to ensure safe identifier
642+
// Table names in ObjectQL are validated and should be safe, but we add extra protection
643+
const safeTableName = tableName.replace(/[^a-zA-Z0-9_]/g, '');
644+
const result = await this.knex.raw(`PRAGMA foreign_key_list(${safeTableName})`);
642645

643646
for (const row of result) {
644647
foreignKeys.push({
@@ -689,7 +692,10 @@ export class SqlDriver implements Driver {
689692
primaryKeys.push(row.column_name);
690693
}
691694
} else if (this.config.client === 'sqlite3') {
692-
const result = await this.knex.raw(`PRAGMA table_info(${tableName})`);
695+
// SQLite PRAGMA doesn't support parameter binding, so we need to ensure safe identifier
696+
// Table names in ObjectQL are validated and should be safe, but we add extra protection
697+
const safeTableName = tableName.replace(/[^a-zA-Z0-9_]/g, '');
698+
const result = await this.knex.raw(`PRAGMA table_info(${safeTableName})`);
693699

694700
for (const row of result) {
695701
if (row.pk === 1) {

packages/foundation/core/src/app.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { ObjectRepository } from './repository';
2121
import { executeActionHelper, registerActionHelper, ActionEntry } from './action';
2222
import { registerHookHelper, triggerHookHelper, HookEntry } from './hook';
2323
import { registerObjectHelper, getConfigsHelper } from './object';
24+
import { convertIntrospectedSchemaToObjects } from './util';
2425

2526
export class ObjectQL implements IObjectQL {
2627
public metadata: MetadataRegistry;
@@ -183,9 +184,6 @@ export class ObjectQL implements IObjectQL {
183184
console.log(`Introspecting database schema from datasource '${datasourceName}'...`);
184185
const introspectedSchema = await driver.introspectSchema();
185186

186-
// Import the conversion utility
187-
const { convertIntrospectedSchemaToObjects } = await import('./util');
188-
189187
// Convert introspected schema to ObjectQL objects
190188
const objects = convertIntrospectedSchemaToObjects(introspectedSchema, options);
191189

packages/foundation/core/src/util.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,14 @@ export function convertIntrospectedSchemaToObjects(
123123
fieldConfig.unique = true;
124124
}
125125

126+
// Add max length for text fields
126127
// Add max length for text fields
127128
if (column.maxLength && (fieldType === 'text' || fieldType === 'textarea')) {
128129
fieldConfig.max_length = column.maxLength;
129130
}
130131

131132
// Add default value
132-
if (column.defaultValue !== undefined && column.defaultValue !== null) {
133+
if (column.defaultValue != null) {
133134
fieldConfig.defaultValue = column.defaultValue;
134135
}
135136
}

0 commit comments

Comments
 (0)