Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions apps/client/public/firebase-messaging-sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ importScripts(
'https://www.gstatic.com/firebasejs/9.22.2/firebase-messaging-compat.js'
);

self.addEventListener('install', function () {
self.addEventListener('install', (event) => {
self.skipWaiting();
});

self.addEventListener('activate', function () {
self.addEventListener('activate', (event) => {
clients.claim();
console.log('실행중..');
});

Expand All @@ -33,22 +34,25 @@ const messaging = firebase.messaging();
messaging.onBackgroundMessage((payload) => {
console.log('Received background message ', payload);

const notificationTitle = payload.notification?.title ?? 'pinback';
const url = payload.data?.url || 'https://www.pinback.today';

const notificationTitle = 'pinback'; // 무조건 기본값
const notificationOptions = {
body: payload.data?.body ?? '저장한 북마크를 확인해 보세요!',
icon: payload.data?.icon ?? '/FCM-IMG.png',
data: {
url: 'https://www.pinback.today',
},
body: '저장한 북마크를 확인해 보세요!',
icon: '/FCM-IMG.png',
data: { url },
requireInteraction: true,
renotify: true,
};
Comment on lines +37 to 46
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

URL 검증 누락으로 인한 보안 취약점

payload.data?.url에서 추출된 URL을 검증 없이 사용하고 있습니다. 악의적인 FCM 메시지가 javascript:, data:, 또는 기타 위험한 스킴을 포함한 URL을 전달할 수 있어 클릭 시 XSS 공격에 노출될 수 있습니다.

다음 diff를 적용하여 URL 스킴을 검증하세요:

- const url = payload.data?.url || 'https://www.pinback.today';
+ const rawUrl = payload.data?.url || 'https://www.pinback.today';
+ let url;
+ try {
+   const parsedUrl = new URL(rawUrl);
+   // HTTP/HTTPS만 허용
+   if (parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:') {
+     url = rawUrl;
+   } else {
+     console.warn('Invalid URL scheme:', parsedUrl.protocol);
+     url = 'https://www.pinback.today';
+   }
+ } catch (e) {
+   console.warn('Invalid URL:', rawUrl);
+   url = 'https://www.pinback.today';
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const url = payload.data?.url || 'https://www.pinback.today';
const notificationTitle = 'pinback'; // 무조건 기본값
const notificationOptions = {
body: payload.data?.body ?? '저장한 북마크를 확인해 보세요!',
icon: payload.data?.icon ?? '/FCM-IMG.png',
data: {
url: 'https://www.pinback.today',
},
body: '저장한 북마크를 확인해 보세요!',
icon: '/FCM-IMG.png',
data: { url },
requireInteraction: true,
renotify: true,
};
const rawUrl = payload.data?.url || 'https://www.pinback.today';
let url;
try {
const parsedUrl = new URL(rawUrl);
// HTTP/HTTPS만 허용
if (parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:') {
url = rawUrl;
} else {
console.warn('Invalid URL scheme:', parsedUrl.protocol);
url = 'https://www.pinback.today';
}
} catch (e) {
console.warn('Invalid URL:', rawUrl);
url = 'https://www.pinback.today';
}
const notificationTitle = 'pinback'; // 무조건 기본값
const notificationOptions = {
body: '저장한 북마크를 확인해 보세요!',
icon: '/FCM-IMG.png',
data: { url },
requireInteraction: true,
renotify: true,
};
🤖 Prompt for AI Agents
In apps/client/public/firebase-messaging-sw.js around lines 37 to 46, the code
uses payload.data?.url without validation which allows dangerous schemes
(javascript:, data:, etc.); validate and sanitize the URL before using it by
parsing with the URL constructor inside a try/catch, ensure the protocol is
either "http:" or "https:", and if parsing fails or the protocol is not allowed
fall back to the safe default 'https://www.pinback.today'; assign this
validated/sanitized URL to notificationOptions.data.url (do not use the raw
payload value).


self.registration.showNotification(notificationTitle, notificationOptions);
});

self.addEventListener('notificationclick', (event) => {
event.notification.close();

const url = event.notification.data?.url || 'https://www.pinback.today';

event.waitUntil(
clients
.matchAll({ type: 'window', includeUncontrolled: true })
Expand All @@ -59,7 +63,7 @@ self.addEventListener('notificationclick', (event) => {
}
}
if (clients.openWindow) {
return clients.openWindow('https://www.pinback.today');
return clients.openWindow(url);
}
})
);
Expand Down
Loading