mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-12 18:15:48 +00:00
fix(browser): block sensitive header intercept matchers
Squash merge PR #1294 into dev.
This commit is contained in:
1 parent
1a06ead908
commit
a86486497b
2 files changed
+63
-1
No files matched your search
@@ -83,6 +83,16 @@ const TOOL_HOVER = 'browser_hover';
|
|||||||
const TOOL_QUERY = 'browser_query';
|
const TOOL_QUERY = 'browser_query';
|
||||||
const TOOL_TAKE_ELEMENT_SCREENSHOT = 'browser_take_element_screenshot';
|
const TOOL_TAKE_ELEMENT_SCREENSHOT = 'browser_take_element_screenshot';
|
||||||
const TOOL_WAIT_FOR_EVENT = 'browser_wait_for_event';
|
const TOOL_WAIT_FOR_EVENT = 'browser_wait_for_event';
|
||||||
|
const SENSITIVE_INTERCEPT_HEADER_NAMES = new Set([
|
||||||
|
'authorization',
|
||||||
|
'cookie',
|
||||||
|
'cookie2',
|
||||||
|
'proxy-authorization',
|
||||||
|
'x-api-key',
|
||||||
|
'x-api-token',
|
||||||
|
'x-auth-token',
|
||||||
|
]);
|
||||||
|
|
||||||
const TOOL_NAMES = [
|
const TOOL_NAMES = [
|
||||||
TOOL_SESSION_INFO,
|
TOOL_SESSION_INFO,
|
||||||
TOOL_URL_TITLE,
|
TOOL_URL_TITLE,
|
||||||
@@ -612,10 +622,15 @@ function getTools() {
|
|||||||
urlRegex: { type: 'string' },
|
urlRegex: { type: 'string' },
|
||||||
headerMatchers: {
|
headerMatchers: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
description:
|
||||||
|
'Match non-sensitive request headers. Cookie, Authorization, and token headers are not allowed.',
|
||||||
items: {
|
items: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
name: { type: 'string' },
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'Non-sensitive request header name to match.',
|
||||||
|
},
|
||||||
valueIncludes: { type: 'string' },
|
valueIncludes: { type: 'string' },
|
||||||
valueRegex: { type: 'string' },
|
valueRegex: { type: 'string' },
|
||||||
},
|
},
|
||||||
@@ -1379,6 +1394,10 @@ function parseOptionalPriority(value) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSensitiveInterceptHeaderName(name) {
|
||||||
|
return SENSITIVE_INTERCEPT_HEADER_NAMES.has(name.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
function parseOptionalHeaderMatchers(value) {
|
function parseOptionalHeaderMatchers(value) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
return [];
|
return [];
|
||||||
@@ -1391,6 +1410,9 @@ function parseOptionalHeaderMatchers(value) {
|
|||||||
throw new Error('headerMatchers entries must be objects');
|
throw new Error('headerMatchers entries must be objects');
|
||||||
}
|
}
|
||||||
const name = requireNonEmptyString(entry.name, 'headerMatchers.name');
|
const name = requireNonEmptyString(entry.name, 'headerMatchers.name');
|
||||||
|
if (isSensitiveInterceptHeaderName(name)) {
|
||||||
|
throw new Error(`headerMatchers.name cannot target sensitive request header: ${name}`);
|
||||||
|
}
|
||||||
const valueIncludes =
|
const valueIncludes =
|
||||||
entry.valueIncludes === undefined
|
entry.valueIncludes === undefined
|
||||||
? ''
|
? ''
|
||||||
|
|||||||
@@ -1779,6 +1779,46 @@ describe('ccs-browser MCP server - session and interception', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('rejects intercept rules that match sensitive request headers', async () => {
|
||||||
|
const responses = await runMcpRequests(
|
||||||
|
[{ id: 'page-1', title: 'Home', currentUrl: 'https://example.com/' }],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: 1003,
|
||||||
|
method: 'tools/call',
|
||||||
|
params: {
|
||||||
|
name: 'browser_add_intercept_rule',
|
||||||
|
arguments: {
|
||||||
|
headerMatchers: [{ name: 'Cookie', valueRegex: '^session=' }],
|
||||||
|
action: 'continue',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: 1004,
|
||||||
|
method: 'tools/call',
|
||||||
|
params: {
|
||||||
|
name: 'browser_add_intercept_rule',
|
||||||
|
arguments: {
|
||||||
|
headerMatchers: [{ name: 'authorization', valueIncludes: 'Bearer ' }],
|
||||||
|
action: 'continue',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const id of [1003, 1004]) {
|
||||||
|
const response = responses.find((message) => message.id === id);
|
||||||
|
expect((response?.result as { isError?: boolean }).isError).toBe(true);
|
||||||
|
expect(getResponseText(response)).toContain(
|
||||||
|
'Browser MCP failed: headerMatchers.name cannot target sensitive request header'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('removes fulfill rules and request summaries after the bound page is closed', async () => {
|
it('removes fulfill rules and request summaries after the bound page is closed', async () => {
|
||||||
const responses = await runMcpRequests(
|
const responses = await runMcpRequests(
|
||||||
[
|
[
|
||||||
|
|||||||
Reference in new issue
Block a user