Skip to content

Commit 9a6ea91

Browse files
committed
Prevent prompt injection by validating target URL origin during chat initialization
- [Pasted text] ├── apps │ └── browser │ └── src │ ├── background │ │ ├── clear-chat-init-data.ts │ │ ├── main.ts │ │ ├── message-handler.ts │ │ └── websocket.ts │ ├── content-scripts │ │ └── send-prompt-content-script │ │ ├── chatbots │ │ │ └── open-webui.ts │ │ └── send-prompt-content-script.ts │ ├── manifest.json │ └── types │ └── messages.ts └── packages └── shared └── src └── types └── websocket-message.ts
1 parent b0e03aa commit 9a6ea91

2 files changed

Lines changed: 24 additions & 27 deletions

File tree

‎apps/browser/src/background/message-handler.ts‎

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,6 @@ export const handle_messages = (message: WebSocketMessage) => {
2828
}
2929
}
3030

31-
const generate_alphanumeric_id = async (
32-
keyspace: string,
33-
length: number = 3
34-
): Promise<string> => {
35-
const characters =
36-
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
37-
let attempts = 0
38-
39-
while (attempts < 1000) {
40-
let result = ''
41-
for (let i = 0; i < length; i++) {
42-
result += characters.charAt(Math.floor(Math.random() * characters.length))
43-
}
44-
const storage_key = `${keyspace}:${result}`
45-
const existing = await browser.storage.local.get(storage_key)
46-
if (!existing[storage_key]) {
47-
return result
48-
}
49-
attempts++
50-
}
51-
52-
throw new Error('Unable to generate a unique ID after maximum attempts')
53-
}
54-
5531
const check_browser_focus = async (): Promise<boolean> => {
5632
const windows = await browser.windows.getAll()
5733
return windows.some((win) => win.focused)
@@ -80,7 +56,7 @@ const process_next_chat = async () => {
8056

8157
const current_chat_message = current_queue_item.message
8258

83-
const batch_id = await generate_alphanumeric_id('chat-init')
59+
const batch_id = crypto.randomUUID()
8460

8561
await browser.storage.local.set({
8662
[`chat-init:${batch_id}`]: {
@@ -119,7 +95,11 @@ const process_next_chat = async () => {
11995

12096
let tab_reused = false
12197

122-
if (last_opened_tab_id !== undefined && is_finished_responding && last_opened_tab_injected_apply_button) {
98+
if (
99+
last_opened_tab_id !== undefined &&
100+
is_finished_responding &&
101+
last_opened_tab_injected_apply_button
102+
) {
123103
try {
124104
const tab = await browser.tabs.get(last_opened_tab_id)
125105
if (tab.active) {
@@ -143,13 +123,17 @@ const process_next_chat = async () => {
143123
last_opened_tab_id = new_tab.id
144124
}
145125

146-
last_opened_tab_injected_apply_button = current_chat_message.inject_apply_response_button ?? false
126+
last_opened_tab_injected_apply_button =
127+
current_chat_message.inject_apply_response_button ?? false
147128
is_finished_responding = false
148129

149130
current_queue_item.timeout_id = setTimeout(() => {
150131
console.warn(
151132
`Chat initialization timeout for ${current_chat_message.url}. Moving to next chat.`
152133
)
134+
browser.storage.local.remove(`chat-init:${batch_id}`).catch((e) => {
135+
console.error('Failed to clean up chat init data on timeout', e)
136+
})
153137
chat_queue.shift()
154138
process_next_chat()
155139
}, CHAT_INITIALIZATION_TIMEOUT) as unknown as number

‎apps/browser/src/content-scripts/send-prompt-content-script/send-prompt-content-script.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,19 @@ const main = async () => {
216216
return
217217
}
218218

219+
try {
220+
const target_url = new URL(current_chat.url)
221+
if (window.location.origin != target_url.origin) {
222+
console.warn(
223+
'Origin mismatch: preventing prompt injection on incorrect domain.'
224+
)
225+
return
226+
}
227+
} catch (e) {
228+
console.error('Invalid target URL', e)
229+
return
230+
}
231+
219232
if (chatbot?.wait_until_ready) {
220233
await chatbot.wait_until_ready()
221234
}

0 commit comments

Comments
 (0)