Merge pull request #230 from modelcontextprotocol/fix/chrome-applescript-tab-id-sanitize
fix(examples/chrome-applescript): sanitize tab_id to prevent AppleScript injection
This commit is contained in:
commit
e2d6196a39
1 changed files with 32 additions and 11 deletions
|
|
@ -82,12 +82,28 @@ class ChromeControlServer {
|
|||
}
|
||||
}
|
||||
|
||||
// Coerce tab_id to a safe numeric value before interpolating into
|
||||
// AppleScript. inputSchema type:"number" is advisory — runtime may receive
|
||||
// a string, which would otherwise be injected into the osascript template.
|
||||
toSafeTabId(tabId) {
|
||||
if (tabId === null || tabId === undefined) return null;
|
||||
const n = Number.parseInt(tabId, 10);
|
||||
if (Number.isNaN(n)) {
|
||||
throw new Error("tab_id must be a number");
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
async findTabById(tabId) {
|
||||
const safeTabId = this.toSafeTabId(tabId);
|
||||
if (safeTabId === null) {
|
||||
return { w: null, t: null, found: false };
|
||||
}
|
||||
const script = `
|
||||
tell application "Google Chrome"
|
||||
repeat with w in windows
|
||||
repeat with t in tabs of w
|
||||
if (id of t as string) is "${tabId}" then
|
||||
if (id of t as string) is "${safeTabId}" then
|
||||
return {w, t, true}
|
||||
end if
|
||||
end repeat
|
||||
|
|
@ -103,7 +119,8 @@ class ChromeControlServer {
|
|||
operation,
|
||||
successMessage = "Operation completed",
|
||||
) {
|
||||
if (!tabId) {
|
||||
const safeTabId = this.toSafeTabId(tabId);
|
||||
if (safeTabId === null) {
|
||||
// No tab ID, execute on active tab
|
||||
return this.executeAppleScript(operation.activeScript);
|
||||
}
|
||||
|
|
@ -112,7 +129,7 @@ class ChromeControlServer {
|
|||
tell application "Google Chrome"
|
||||
repeat with w in windows
|
||||
repeat with t in tabs of w
|
||||
if (id of t as string) is "${tabId}" then
|
||||
if (id of t as string) is "${safeTabId}" then
|
||||
${operation.tabScript}
|
||||
return "${successMessage}"
|
||||
end if
|
||||
|
|
@ -551,6 +568,7 @@ class ChromeControlServer {
|
|||
"JavaScript code is required and must be a string",
|
||||
);
|
||||
}
|
||||
const safeTabId = this.toSafeTabId(tab_id);
|
||||
|
||||
// Wrap the code to capture console.log outputs
|
||||
const wrappedCode = `
|
||||
|
|
@ -628,12 +646,13 @@ class ChromeControlServer {
|
|||
|
||||
const escapedCode = this.escapeForAppleScript(wrappedCode);
|
||||
|
||||
const script = tab_id
|
||||
const script =
|
||||
safeTabId != null
|
||||
? `
|
||||
tell application "Google Chrome"
|
||||
repeat with w in windows
|
||||
repeat with t in tabs of w
|
||||
if (id of t as string) is "${tab_id}" then
|
||||
if (id of t as string) is "${safeTabId}" then
|
||||
set result to execute t javascript "${escapedCode}"
|
||||
return result
|
||||
end if
|
||||
|
|
@ -695,14 +714,16 @@ class ChromeControlServer {
|
|||
|
||||
case "get_page_content": {
|
||||
const { tab_id } = args;
|
||||
const safeTabId = this.toSafeTabId(tab_id);
|
||||
|
||||
const jsCode = "document.body.innerText";
|
||||
const script = tab_id
|
||||
const script =
|
||||
safeTabId != null
|
||||
? `
|
||||
tell application "Google Chrome"
|
||||
repeat with w in windows
|
||||
repeat with t in tabs of w
|
||||
if (id of t as string) is "${tab_id}" then
|
||||
if (id of t as string) is "${safeTabId}" then
|
||||
set pageContent to execute t javascript "${jsCode}"
|
||||
return pageContent
|
||||
end if
|
||||
|
|
|
|||
Loading…
Reference in a new issue