Skip to content

Commit 1f70567

Browse files
ddworkensmola
andauthored
Add basic mitigation against postgres queries injecting to trigger writes or other dangerous actions (#1889)
Co-authored-by: Santiago Mola <santiago.mola@datadoghq.com>
1 parent 47fad9a commit 1f70567

File tree

2 files changed

+15
-2
lines changed

2 files changed

+15
-2
lines changed

src/postgres/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
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.
44

5+
> [!CAUTION]
6+
> 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.
7+
58
## Components
69

710
### Tools

src/postgres/index.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
115115
const client = await pool.connect();
116116
try {
117117
await client.query("BEGIN TRANSACTION READ ONLY");
118-
const result = await client.query(sql);
118+
// Use a prepared statement to isolate the query. This approach
119+
// ensures that the SQL text is parsed as a single statement, preventing
120+
// malicious injections like "SELECT 1; COMMIT; DROP TABLE users;" which
121+
// could bypass the read-only transaction by committing it prematurely.
122+
const result = await client.query({
123+
name: "isolated-statement",
124+
text: sql,
125+
values: [],
126+
});
119127
return {
120128
content: [{ type: "text", text: JSON.stringify(result.rows, null, 2) }],
121129
isError: false,
@@ -129,7 +137,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
129137
console.warn("Could not roll back transaction:", error),
130138
);
131139

132-
client.release();
140+
// Release the client with destroy=true to ensure complete cleanup of the
141+
// database session, preventing any potential state leakage between queries.
142+
client.release(true);
133143
}
134144
}
135145
throw new Error(`Unknown tool: ${request.params.name}`);

0 commit comments

Comments
 (0)