diff --git a/docs/releases.md b/docs/releases.md index 036b2120..1d4d8590 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -1898,6 +1898,7 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release **Bug fixes + maintenance:** * Remove `stacktrace-js`, `stacktrace-gps`, `humanize-duration`, and `js-base64` from the web app to reduce dependency and security footprint +* Restrict the publish dialog's local file preview to safe image types (png/jpg/gif/webp) to prevent same-origin script execution from blob URLs when previewing a crafted SVG ([GHSA-j8hr-p342-xrmh](https://github.com/binwiederhier/ntfy/security/advisories/GHSA-j8hr-p342-xrmh), thanks to [@Venukamatchi](https://github.com/Venukamatchi) for reporting) ## ntfy Android v1.25.x (UNRELEASED) diff --git a/web/src/app/notificationUtils.js b/web/src/app/notificationUtils.js index 070f8231..2453075a 100644 --- a/web/src/app/notificationUtils.js +++ b/web/src/app/notificationUtils.js @@ -35,7 +35,7 @@ export const formatMessage = (m) => { return m.message || ""; }; -const imageRegex = /\.(png|jpe?g|gif|webp)$/i; +export const imageRegex = /\.(png|jpe?g|gif|webp)$/i; export const isImage = (attachment) => { if (!attachment) return false; diff --git a/web/src/app/utils.js b/web/src/app/utils.js index a6fa07b0..2a62aa38 100644 --- a/web/src/app/utils.js +++ b/web/src/app/utils.js @@ -145,8 +145,7 @@ export const hashCode = (s) => { * which is expected by `` and `Intl.DateTimeFormat`. Falls back to "en" * if the input is missing or not a string. */ -export const getKebabCaseLangStr = (language) => - typeof language === "string" && language.length > 0 ? language.replace(/_/g, "-") : "en"; +export const getKebabCaseLangStr = (language) => (typeof language === "string" && language.length > 0 ? language.replace(/_/g, "-") : "en"); export const formatShortDateTime = (timestamp, language) => new Intl.DateTimeFormat(getKebabCaseLangStr(language), { diff --git a/web/src/components/AttachmentIcon.jsx b/web/src/components/AttachmentIcon.jsx index b7bf6b50..0cdcb0b0 100644 --- a/web/src/components/AttachmentIcon.jsx +++ b/web/src/components/AttachmentIcon.jsx @@ -31,18 +31,24 @@ const AttachmentIcon = (props) => { imageFile = fileDocument; imageLabel = t("notifications_attachment_file_document"); } + const icon = ( + + ); + if (!props.href) { + return icon; + } return ( - - + + {icon} ); }; diff --git a/web/src/components/PublishDialog.jsx b/web/src/components/PublishDialog.jsx index 912810b3..c263861a 100644 --- a/web/src/components/PublishDialog.jsx +++ b/web/src/components/PublishDialog.jsx @@ -30,6 +30,7 @@ import priority3 from "../img/priority-3.svg"; import priority4 from "../img/priority-4.svg"; import priority5 from "../img/priority-5.svg"; import { formatBytes, maybeWithAuth, topicShortUrl, topicUrl, validTopic, validUrl } from "../app/utils"; +import { imageRegex } from "../app/notificationUtils"; import AttachmentIcon from "./AttachmentIcon"; import DialogFooter from "./DialogFooter"; import api from "../app/Api"; @@ -805,7 +806,7 @@ const AttachmentBox = (props) => { borderRadius: "4px", }} > - +