diff --git a/server-ce/hotfix/4.2.5/Dockerfile b/server-ce/hotfix/4.2.5/Dockerfile
new file mode 100644
index 0000000000..b140c0d990
--- /dev/null
+++ b/server-ce/hotfix/4.2.5/Dockerfile
@@ -0,0 +1,29 @@
+FROM sharelatex/sharelatex:4.2.4
+
+# apply an override to the swagger-tools package to force security updates to multer and qs
+# from https://github.com/overleaf/internal/pull/18433
+COPY pr_18433.patch .
+RUN patch -p1 < pr_18433.patch && rm pr_18433.patch
+RUN npm install --include-workspace-root -w services/history-v1 swagger-tools@0.10.4 && rm -rf /root/.cache /root/.npm $(find /tmp/ -mindepth 1 -maxdepth 1)
+
+# remove google-cloud packages which are unused in server-pro have a vulnerable dependency
+RUN npm uninstall -w libraries/logger @google-cloud/logging-bunyan
+RUN npm uninstall -w libraries/metrics @google-cloud/opentelemetry-cloud-trace-exporter @google-cloud/profiler
+
+# the passport-twitter package has been removed from the monorepo
+RUN npm uninstall -w services/web passport-twitter
+
+# remove the unused services/web/scripts/translations directory
+RUN rm -r services/web/scripts/translations
+
+COPY pr_18393.patch .
+RUN patch -p1 < pr_18393.patch && rm pr_18393.patch
+COPY pr_18444.patch .
+RUN patch -p1 < pr_18444.patch && rm pr_18444.patch
+COPY pr_18819.patch .
+RUN patch -p1 < pr_18819.patch && rm pr_18819.patch
+COPY pr_18570.patch .
+RUN patch -p1 < pr_18570.patch && rm pr_18570.patch
+
+# Recompile frontend assets
+RUN node genScript compile | bash
diff --git a/server-ce/hotfix/4.2.5/pr_18393.patch b/server-ce/hotfix/4.2.5/pr_18393.patch
new file mode 100644
index 0000000000..5af1af7750
--- /dev/null
+++ b/server-ce/hotfix/4.2.5/pr_18393.patch
@@ -0,0 +1,111 @@
+diff --git a/services/web/frontend/js/features/source-editor/components/command-tooltip/href-tooltip.tsx b/services/web/frontend/js/features/source-editor/components/command-tooltip/href-tooltip.tsx
+index a0d681d9cb5..2f9a4333cd6 100644
+--- a/services/web/frontend/js/features/source-editor/components/command-tooltip/href-tooltip.tsx
++++ b/services/web/frontend/js/features/source-editor/components/command-tooltip/href-tooltip.tsx
+@@ -17,6 +17,7 @@ import {
+ import { Button, ControlLabel, FormControl, FormGroup } from 'react-bootstrap'
+ import Icon from '../../../../shared/components/icon'
+ import { EditorState } from '@codemirror/state'
++import { openURL } from '@/features/source-editor/utils/url'
+
+ export const HrefTooltipContent: FC = () => {
+ const state = useCodeMirrorStateContext()
+@@ -108,7 +109,7 @@ export const HrefTooltipContent: FC = () => {
+ className="ol-cm-command-tooltip-link"
+ onClick={() => {
+ // TODO: unescape content
+- window.open(url, '_blank')
++ openURL(url)
+ }}
+ >
+
+diff --git a/services/web/frontend/js/features/source-editor/components/command-tooltip/url-tooltip.tsx b/services/web/frontend/js/features/source-editor/components/command-tooltip/url-tooltip.tsx
+index c51b497de01..632d71dd031 100644
+--- a/services/web/frontend/js/features/source-editor/components/command-tooltip/url-tooltip.tsx
++++ b/services/web/frontend/js/features/source-editor/components/command-tooltip/url-tooltip.tsx
+@@ -9,6 +9,7 @@ import {
+ } from '../../lezer-latex/latex.terms.mjs'
+ import Icon from '../../../../shared/components/icon'
+ import { EditorState } from '@codemirror/state'
++import { openURL } from '@/features/source-editor/utils/url'
+
+ export const UrlTooltipContent: FC = () => {
+ const { t } = useTranslation()
+@@ -23,7 +24,7 @@ export const UrlTooltipContent: FC = () => {
+ onClick={() => {
+ const url = readUrl(state)
+ if (url) {
+- window.open(url, '_blank')
++ openURL(url)
+ }
+ }}
+ >
+diff --git a/services/web/frontend/js/features/source-editor/utils/url.ts b/services/web/frontend/js/features/source-editor/utils/url.ts
+new file mode 100644
+index 00000000000..8bfc9bdeab8
+--- /dev/null
++++ b/services/web/frontend/js/features/source-editor/utils/url.ts
+@@ -0,0 +1,11 @@
++const ALLOWED_PROTOCOLS = ['https:', 'http:']
++
++export const openURL = (content: string) => {
++ const url = new URL(content, document.location.href)
++
++ if (!ALLOWED_PROTOCOLS.includes(url.protocol)) {
++ throw new Error(`Not opening URL with protocol ${url.protocol}`)
++ }
++
++ window.open(url, '_blank')
++}
+diff --git a/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-command-tooltip.spec.tsx b/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-command-tooltip.spec.tsx
+index 837f90a64ab..d46b522a116 100644
+--- a/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-command-tooltip.spec.tsx
++++ b/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-command-tooltip.spec.tsx
+@@ -54,8 +54,8 @@ describe(' command tooltip in Visual mode', function () {
+ // open the link
+ cy.findByRole('button', { name: 'Go to page' }).click()
+ cy.get('@window-open').should(
+- 'have.been.calledOnceWithExactly',
+- 'https://example.com',
++ 'have.been.calledWithMatch',
++ Cypress.sinon.match.has('href', 'https://example.com/'),
+ '_blank'
+ )
+
+@@ -112,8 +112,8 @@ describe(' command tooltip in Visual mode', function () {
+ // open the link
+ cy.findByRole('button', { name: 'Go to page' }).click()
+ cy.get('@window-open').should(
+- 'have.been.calledOnceWithExactly',
+- 'https://example.com',
++ 'have.been.calledWithMatch',
++ Cypress.sinon.match.has('href', 'https://example.com/'),
+ '_blank'
+ )
+ })
+diff --git a/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-tooltips.spec.tsx b/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-tooltips.spec.tsx
+index c6e28f9eeeb..106a80ba187 100644
+--- a/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-tooltips.spec.tsx
++++ b/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-tooltips.spec.tsx
+@@ -42,8 +42,8 @@ describe(' tooltips in Visual mode', function () {
+ })
+ cy.findByRole('button', { name: 'Go to page' }).click()
+ cy.get('@open-window').should(
+- 'have.been.calledOnceWithExactly',
+- 'https://example.com/foo',
++ 'have.been.calledWithMatch',
++ Cypress.sinon.match.has('href', 'https://example.com/foo'),
+ '_blank'
+ )
+ cy.findByRole('button', { name: 'Remove link' }).click()
+@@ -62,8 +62,8 @@ describe(' tooltips in Visual mode', function () {
+ })
+ cy.findByRole('button', { name: 'Go to page' }).click()
+ cy.get('@open-window').should(
+- 'have.been.calledOnceWithExactly',
+- 'https://example.com',
++ 'have.been.calledWithMatch',
++ Cypress.sinon.match.has('href', 'https://example.com/'),
+ '_blank'
+ )
+ })
diff --git a/server-ce/hotfix/4.2.5/pr_18433.patch b/server-ce/hotfix/4.2.5/pr_18433.patch
new file mode 100644
index 0000000000..1e14f239ab
--- /dev/null
+++ b/server-ce/hotfix/4.2.5/pr_18433.patch
@@ -0,0 +1,63 @@
+diff --git a/package-lock.json b/package-lock.json
+index b9eba6086b..bb1a5cebaf 100644
+--- a/package-lock.json
++++ b/package-lock.json
+@@ -70674,8 +70674,7 @@
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "multer": {
+- "version": "1.4.4",
+- "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz",
++ "version": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz",
+ "integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==",
+ "requires": {
+ "append-field": "^1.0.0",
+@@ -76995,10 +76994,10 @@
+ "js-yaml": "^3.3.1",
+ "json-refs": "^3.0.2",
+ "lodash": "^4.17.4",
+- "multer": "^1.1.0",
++ "multer": "1.4.5-lts.1",
+ "parseurl": "^1.3.0",
+ "path-to-regexp": "^2.0.0",
+- "qs": "^6.0.3",
++ "qs": "6.5.3",
+ "serve-static": "^1.10.0",
+ "spark-md5": "^3.0.0",
+ "superagent": "^3.5.2",
+@@ -77035,7 +77034,7 @@
+ "http-errors": "~1.6.2",
+ "iconv-lite": "0.4.19",
+ "on-finished": "~2.3.0",
+- "qs": "6.5.1",
++ "qs": "6.5.3",
+ "raw-body": "2.3.2",
+ "type-is": "~1.6.15"
+ },
+@@ -77109,8 +77108,7 @@
+ "integrity": "sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w=="
+ },
+ "qs": {
+- "version": "6.5.1",
+- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
++ "version": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
+ "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
+ },
+ "raw-body": {
+diff --git a/package.json b/package.json
+index f092472caf..329d4fc5ce 100644
+--- a/package.json
++++ b/package.json
+@@ -1,6 +1,12 @@
+ {
+ "name": "overleaf",
+ "private": true,
++ "overrides": {
++ "swagger-tools": {
++ "multer": "1.4.5-lts.1",
++ "qs": "6.5.3"
++ }
++ },
+ "dependencies": {
+ "patch-package": "^8.0.0"
+ },
diff --git a/server-ce/hotfix/4.2.5/pr_18444.patch b/server-ce/hotfix/4.2.5/pr_18444.patch
new file mode 100644
index 0000000000..e79fe18550
--- /dev/null
+++ b/server-ce/hotfix/4.2.5/pr_18444.patch
@@ -0,0 +1,41 @@
+diff --git a/services/web/frontend/js/features/file-view/components/file-view-pdf.tsx b/services/web/frontend/js/features/file-view/components/file-view-pdf.tsx
+index 4d3b80bb9a2..3efc61a2199 100644
+--- a/services/web/frontend/js/features/file-view/components/file-view-pdf.tsx
++++ b/services/web/frontend/js/features/file-view/components/file-view-pdf.tsx
+@@ -33,7 +33,10 @@ const FileViewPdf: FC<{
+ return
+ }
+
+- const pdf = await PDFJS.getDocument(preview.url).promise
++ const pdf = await PDFJS.getDocument({
++ url: preview.url,
++ isEvalSupported: false,
++ }).promise
+
+ // bail out if loading the PDF took too long
+ if (!mountedRef.current) {
+diff --git a/services/web/frontend/js/features/pdf-preview/util/pdf-js-wrapper.js b/services/web/frontend/js/features/pdf-preview/util/pdf-js-wrapper.js
+index 9b419b1397f..6a92630a215 100644
+--- a/services/web/frontend/js/features/pdf-preview/util/pdf-js-wrapper.js
++++ b/services/web/frontend/js/features/pdf-preview/util/pdf-js-wrapper.js
+@@ -96,6 +96,7 @@ export default class PDFJSWrapper {
+ rangeChunkSize,
+ disableAutoFetch: true,
+ disableStream,
++ isEvalSupported: false,
+ textLayerMode: 2, // PDFJSViewer.TextLayerMode.ENABLE,
+ range: rangeTransport,
+ })
+diff --git a/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/graphics.ts b/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/graphics.ts
+index 7321f9e02b5..f6c744aaec2 100644
+--- a/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/graphics.ts
++++ b/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/graphics.ts
+@@ -143,7 +143,7 @@ export class GraphicsWidget extends WidgetType {
+ return
+ }
+
+- const pdf = await PDFJS.getDocument(url).promise
++ const pdf = await PDFJS.getDocument({ url, isEvalSupported: false }).promise
+ const page = await pdf.getPage(1)
+
+ // bail out if loading the PDF took too long
diff --git a/server-ce/hotfix/4.2.5/pr_18570.patch b/server-ce/hotfix/4.2.5/pr_18570.patch
new file mode 100644
index 0000000000..05bc9f5531
--- /dev/null
+++ b/server-ce/hotfix/4.2.5/pr_18570.patch
@@ -0,0 +1,30 @@
+--- a/genScript.js
++++ b/genScript.js
+@@ -5,16 +5,26 @@ console.log('set -ex')
+
+ switch (process.argv.pop()) {
+ case 'install':
+- console.log('npm ci')
++ console.log('npm install --omit=dev')
+ break
+ case 'compile':
+ for (const service of services) {
+ console.log('pushd', `services/${service.name}`)
+ switch (service.name) {
+ case 'web':
++ // Avoid downloading of cypress
++ console.log('export CYPRESS_INSTALL_BINARY=0')
++
++ // install webpack and frontend dependencies
++ console.log('npm install --include=dev')
++ // install misplaced dependencies (fixed via 18389)
++ console.log('pushd ../../ && npm install --include=dev --workspaces=false && popd')
++ // run webpack
+ console.log('npm run webpack:production')
+ // drop webpack/babel cache
+ console.log('rm -rf node_modules/.cache')
++ // uninstall webpack and frontend dependencies
++ console.log('pushd ../../ && npm install --omit=dev && popd')
+ break
+ default:
+ console.log(`echo ${service.name} does not require a compilation`)
diff --git a/server-ce/hotfix/4.2.5/pr_18819.patch b/server-ce/hotfix/4.2.5/pr_18819.patch
new file mode 100644
index 0000000000..858c044ea5
--- /dev/null
+++ b/server-ce/hotfix/4.2.5/pr_18819.patch
@@ -0,0 +1,17 @@
+--- a/services/web/frontend/js/features/mathjax/load-mathjax.ts
++++ b/services/web/frontend/js/features/mathjax/load-mathjax.ts
+@@ -36,6 +36,15 @@ export const loadMathJax = async () => {
+ },
+ startup: {
+ typeset: false,
++ ready() {
++ window.MathJax.startup.defaultReady()
++ const safe = window.MathJax.startup.document.safe
++ safe.filterAttributes.set('fontfamily', 'filterFontFamily')
++ safe.filterMethods.filterFontFamily = (
++ _safe: any,
++ family: string
++ ) => family.split(/;/)[0]
++ },
+ },
+ }
diff --git a/server-ce/hotfix/5.0.5/Dockerfile b/server-ce/hotfix/5.0.5/Dockerfile
new file mode 100644
index 0000000000..b9ad108a26
--- /dev/null
+++ b/server-ce/hotfix/5.0.5/Dockerfile
@@ -0,0 +1,12 @@
+FROM sharelatex/sharelatex:5.0.4
+
+# Install dev dependencies as part of "genScript compile"
+COPY pr_18570.patch .
+RUN patch -p1 < pr_18570.patch && rm pr_18570.patch
+
+# Adopted from https://github.com/overleaf/internal/pull/18819
+COPY pr_18819.patch .
+RUN patch -p1 < pr_18819.patch && rm pr_18819.patch
+
+# Recompile frontend assets
+RUN node genScript compile | bash
diff --git a/server-ce/hotfix/5.0.5/pr_18570.patch b/server-ce/hotfix/5.0.5/pr_18570.patch
new file mode 100644
index 0000000000..05bc9f5531
--- /dev/null
+++ b/server-ce/hotfix/5.0.5/pr_18570.patch
@@ -0,0 +1,30 @@
+--- a/genScript.js
++++ b/genScript.js
+@@ -5,16 +5,26 @@ console.log('set -ex')
+
+ switch (process.argv.pop()) {
+ case 'install':
+- console.log('npm ci')
++ console.log('npm install --omit=dev')
+ break
+ case 'compile':
+ for (const service of services) {
+ console.log('pushd', `services/${service.name}`)
+ switch (service.name) {
+ case 'web':
++ // Avoid downloading of cypress
++ console.log('export CYPRESS_INSTALL_BINARY=0')
++
++ // install webpack and frontend dependencies
++ console.log('npm install --include=dev')
++ // install misplaced dependencies (fixed via 18389)
++ console.log('pushd ../../ && npm install --include=dev --workspaces=false && popd')
++ // run webpack
+ console.log('npm run webpack:production')
+ // drop webpack/babel cache
+ console.log('rm -rf node_modules/.cache')
++ // uninstall webpack and frontend dependencies
++ console.log('pushd ../../ && npm install --omit=dev && popd')
+ break
+ default:
+ console.log(`echo ${service.name} does not require a compilation`)
diff --git a/server-ce/hotfix/5.0.5/pr_18819.patch b/server-ce/hotfix/5.0.5/pr_18819.patch
new file mode 100644
index 0000000000..83525653da
--- /dev/null
+++ b/server-ce/hotfix/5.0.5/pr_18819.patch
@@ -0,0 +1,17 @@
+--- a/services/web/frontend/js/features/mathjax/load-mathjax.ts
++++ b/services/web/frontend/js/features/mathjax/load-mathjax.ts
+@@ -64,6 +64,15 @@ export const loadMathJax = async (options?: {
+ .findID('Renderer')
+ .disable()
+ },
++ ready() {
++ window.MathJax.startup.defaultReady()
++ const safe = window.MathJax.startup.document.safe
++ safe.filterAttributes.set('fontfamily', 'filterFontFamily')
++ safe.filterMethods.filterFontFamily = (
++ _safe: any,
++ family: string
++ ) => family.split(/;/)[0]
++ },
+ },
+ }