aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Utility/pushEndpoint.ts
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-06-01 15:37:21 +0000
committerFuwn <[email protected]>2026-06-01 15:37:21 +0000
commit662631a27948d431e6bd37fed15077b1bcccc7f8 (patch)
treeb71ddebe246ffb51fb214664233f6a38a26a6211 /src/lib/Utility/pushEndpoint.ts
parentfix(security): authorize shadowHide target in badges endpoint (IDOR) (diff)
downloaddue.moe-662631a27948d431e6bd37fed15077b1bcccc7f8.tar.xz
due.moe-662631a27948d431e6bd37fed15077b1bcccc7f8.zip
fix(security): allow-list web-push endpoints to stop SSRF
Stored push subscriptions carry a client-supplied `endpoint`, and the notifications job POSTed to it with no host check, so a subscription with an internal/metadata URL turned the Trigger.dev worker into a blind SSRF primitive. Add isAllowedPushEndpoint (https + known vendor hosts: FCM, Mozilla, Apple, WNS), skip non-conforming endpoints in the job, and reject them at subscribe time. Browser-minted subscriptions always match a vendor host, so real delivery is unchanged; a behaviour-gate test asserts vendor endpoints pass and internal/non-https/look-alikes fail.
Diffstat (limited to 'src/lib/Utility/pushEndpoint.ts')
-rw-r--r--src/lib/Utility/pushEndpoint.ts26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/lib/Utility/pushEndpoint.ts b/src/lib/Utility/pushEndpoint.ts
new file mode 100644
index 00000000..702164ae
--- /dev/null
+++ b/src/lib/Utility/pushEndpoint.ts
@@ -0,0 +1,26 @@
+/**
+ * Web Push endpoints are minted by the browser's PushManager and always point at
+ * a known vendor push service — the user and the app never choose them. Limiting
+ * outbound delivery to these hosts stops the notifications job from being used as
+ * an SSRF primitive: a stored subscription with an arbitrary `endpoint` would
+ * otherwise have the worker POST to any URL, including internal/metadata hosts.
+ */
+const allowedPushHosts: RegExp[] = [
+ /^fcm\.googleapis\.com$/, // Chrome, Edge, Brave, Opera, Samsung Internet
+ /(^|\.)push\.services\.mozilla\.com$/, // Firefox
+ /^web\.push\.apple\.com$/, // Safari / Apple
+ /(^|\.)notify\.windows\.com$/, // legacy Edge / Windows (WNS)
+];
+
+export const isAllowedPushEndpoint = (endpoint: string): boolean => {
+ try {
+ const url = new URL(endpoint);
+
+ return (
+ url.protocol === "https:" &&
+ allowedPushHosts.some((host) => host.test(url.hostname))
+ );
+ } catch {
+ return false;
+ }
+};