mirror of
https://github.com/Mintplex-Labs/anything-llm
synced 2026-04-25 17:15:37 +02:00
Replace string concatenation with parameterized queries in all database connectors to prevent SQL injection through LLM-generated table names. Changes: - PostgreSQL: Use $1, $2 placeholders with pg client parameterization - MySQL: Use ? placeholders with mysql2 execute() prepared statements - MSSQL: Use @p0 placeholders with request.input() parameterization - Update handlers to support parameterized query objects - Add formatQueryForDisplay() for logging parameterized queries Security: Mitigates potential SQL injection when LLM passes unsanitized user input as table_name parameter to getTableSchemaSql/getTablesSql. GHSA-jwjx-mw2p-5wc7
116 lines
4.1 KiB
JavaScript
116 lines
4.1 KiB
JavaScript
module.exports.SqlAgentGetTableSchema = {
|
|
name: "sql-get-table-schema",
|
|
plugin: function () {
|
|
const {
|
|
listSQLConnections,
|
|
getDBClient,
|
|
} = require("./SQLConnectors/index.js");
|
|
|
|
function formatQueryForDisplay(query, params = []) {
|
|
if (!params.length) return query;
|
|
let formatted = query;
|
|
params.forEach((param, index) => {
|
|
const value = typeof param === "string" ? `'${param}'` : param;
|
|
formatted = formatted.replace(`$${index + 1}`, value);
|
|
formatted = formatted.replace(`@p${index}`, value);
|
|
formatted = formatted.replace("?", value);
|
|
});
|
|
return formatted;
|
|
}
|
|
|
|
return {
|
|
name: "sql-get-table-schema",
|
|
setup(aibitat) {
|
|
aibitat.function({
|
|
super: aibitat,
|
|
name: this.name,
|
|
description:
|
|
"Gets the table schema in SQL for a given `table` and `database_id`",
|
|
examples: [
|
|
{
|
|
prompt: "What does the customers table in access-logs look like?",
|
|
call: JSON.stringify({
|
|
database_id: "access-logs",
|
|
table_name: "customers",
|
|
}),
|
|
},
|
|
{
|
|
prompt:
|
|
"Get me the full name of a company in records-main, the table should be call comps",
|
|
call: JSON.stringify({
|
|
database_id: "records-main",
|
|
table_name: "comps",
|
|
}),
|
|
},
|
|
],
|
|
parameters: {
|
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
type: "object",
|
|
properties: {
|
|
database_id: {
|
|
type: "string",
|
|
description:
|
|
"The database identifier for which we will connect to to query the table schema. This is a required field.",
|
|
},
|
|
table_name: {
|
|
type: "string",
|
|
description:
|
|
"The database identifier for the table name we want the schema for. This is a required field.",
|
|
},
|
|
},
|
|
additionalProperties: false,
|
|
},
|
|
required: ["database_id", "table_name"],
|
|
handler: async function ({ database_id = "", table_name = "" }) {
|
|
this.super.handlerProps.log(`Using the sql-get-table-schema tool.`);
|
|
try {
|
|
const databaseConfig = (await listSQLConnections()).find(
|
|
(db) => db.database_id === database_id
|
|
);
|
|
if (!databaseConfig) {
|
|
this.super.handlerProps.log(
|
|
`sql-get-table-schema to find config!`,
|
|
database_id
|
|
);
|
|
return `No database connection for ${database_id} was found!`;
|
|
}
|
|
|
|
const db = getDBClient(databaseConfig.engine, databaseConfig);
|
|
this.super.introspect(
|
|
`${this.caller}: Querying the table schema for ${table_name} in the ${databaseConfig.database_id} database.`
|
|
);
|
|
|
|
const sqlQuery = db.getTableSchemaSql(table_name);
|
|
const isParameterized =
|
|
typeof sqlQuery === "object" && sqlQuery.query;
|
|
const queryString = isParameterized ? sqlQuery.query : sqlQuery;
|
|
const queryParams = isParameterized ? sqlQuery.params : [];
|
|
|
|
this.super.introspect(
|
|
`Running SQL: ${formatQueryForDisplay(queryString, queryParams)}`
|
|
);
|
|
const result = await db.runQuery(queryString, queryParams);
|
|
|
|
if (result.error) {
|
|
this.super.handlerProps.log(
|
|
`sql-get-table-schema tool reported error`,
|
|
result.error
|
|
);
|
|
this.super.introspect(`Error: ${result.error}`);
|
|
return `There was an error running the query: ${result.error}`;
|
|
}
|
|
|
|
return JSON.stringify(result);
|
|
} catch (e) {
|
|
this.super.handlerProps.log(
|
|
`sql-get-table-schema raised an error. ${e.message}`
|
|
);
|
|
return e.message;
|
|
}
|
|
},
|
|
});
|
|
},
|
|
};
|
|
},
|
|
};
|