Add basic mitigation against postgres queries injecting to trigger writes or other dangerous actions (#1889)
Co-authored-by: Santiago Mola <santiago.mola@datadoghq.com>
This commit is contained in:
parent
47fad9ad59
commit
1f705677a9
2 changed files with 15 additions and 2 deletions
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
A Model Context Protocol server that provides read-only access to PostgreSQL databases. This server enables LLMs to inspect database schemas and execute read-only queries.
|
A Model Context Protocol server that provides read-only access to PostgreSQL databases. This server enables LLMs to inspect database schemas and execute read-only queries.
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
> This server provides database access to AI models. If you need to enforce read-only access for security, create a separate database user with only SELECT permissions instead of relying on this server's built-in restrictions.
|
||||||
|
|
||||||
## Components
|
## Components
|
||||||
|
|
||||||
### Tools
|
### Tools
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
try {
|
try {
|
||||||
await client.query("BEGIN TRANSACTION READ ONLY");
|
await client.query("BEGIN TRANSACTION READ ONLY");
|
||||||
const result = await client.query(sql);
|
// Use a prepared statement to isolate the query. This approach
|
||||||
|
// ensures that the SQL text is parsed as a single statement, preventing
|
||||||
|
// malicious injections like "SELECT 1; COMMIT; DROP TABLE users;" which
|
||||||
|
// could bypass the read-only transaction by committing it prematurely.
|
||||||
|
const result = await client.query({
|
||||||
|
name: "isolated-statement",
|
||||||
|
text: sql,
|
||||||
|
values: [],
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: JSON.stringify(result.rows, null, 2) }],
|
content: [{ type: "text", text: JSON.stringify(result.rows, null, 2) }],
|
||||||
isError: false,
|
isError: false,
|
||||||
|
|
@ -129,7 +137,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||||
console.warn("Could not roll back transaction:", error),
|
console.warn("Could not roll back transaction:", error),
|
||||||
);
|
);
|
||||||
|
|
||||||
client.release();
|
// Release the client with destroy=true to ensure complete cleanup of the
|
||||||
|
// database session, preventing any potential state leakage between queries.
|
||||||
|
client.release(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error(`Unknown tool: ${request.params.name}`);
|
throw new Error(`Unknown tool: ${request.params.name}`);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue