diff --git a/e2e/src/api/specs/shared-link.e2e-spec.ts b/e2e/src/api/specs/shared-link.e2e-spec.ts
index 3918429e4e..154f190f53 100644
--- a/e2e/src/api/specs/shared-link.e2e-spec.ts
+++ b/e2e/src/api/specs/shared-link.e2e-spec.ts
@@ -95,7 +95,7 @@ describe('/shared-links', () => {
expect(resp.status).toBe(200);
expect(resp.header['content-type']).toContain('text/html');
expect(resp.text).toContain(
- ``,
+ ``,
);
});
@@ -103,14 +103,14 @@ describe('/shared-links', () => {
const resp = await request(shareUrl).get(`/${linkWithAlbum.key}`);
expect(resp.status).toBe(200);
expect(resp.header['content-type']).toContain('text/html');
- expect(resp.text).toContain(``);
+ expect(resp.text).toContain(``);
});
it('should have correct asset count in meta tag for shared asset', async () => {
const resp = await request(shareUrl).get(`/${linkWithAssets.key}`);
expect(resp.status).toBe(200);
expect(resp.header['content-type']).toContain('text/html');
- expect(resp.text).toContain(``);
+ expect(resp.text).toContain(``);
});
it('should have fqdn og:image meta tag for shared asset', async () => {
diff --git a/server/package-lock.json b/server/package-lock.json
index 8a2c0c9f25..80de8b37ff 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -59,6 +59,7 @@
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
"sanitize-filename": "^1.6.3",
+ "sanitize-html": "^2.14.0",
"semver": "^7.6.2",
"sharp": "^0.33.0",
"sirv": "^3.0.0",
@@ -91,6 +92,7 @@
"@types/picomatch": "^3.0.0",
"@types/pngjs": "^6.0.5",
"@types/react": "^19.0.0",
+ "@types/sanitize-html": "^2.13.0",
"@types/semver": "^7.5.8",
"@types/supertest": "^6.0.0",
"@types/ua-parser-js": "^0.7.36",
@@ -6042,6 +6044,16 @@
"@types/node": "*"
}
},
+ "node_modules/@types/sanitize-html": {
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.13.0.tgz",
+ "integrity": "sha512-X31WxbvW9TjIhZZNyNBZ/p5ax4ti7qsNDBDEnH4zAgmEh35YnFD1UiS6z9Cd34kKm0LslFW0KPmTQzu/oGtsqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "htmlparser2": "^8.0.0"
+ }
+ },
"node_modules/@types/semver": {
"version": "7.5.8",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
@@ -8931,7 +8943,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -10747,6 +10758,15 @@
"node": ">=0.12.0"
}
},
+ "node_modules/is-plain-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-promise": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
@@ -12394,6 +12414,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/parse-srcset": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
+ "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==",
+ "license": "MIT"
+ },
"node_modules/parse5": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
@@ -14072,6 +14098,20 @@
"truncate-utf8-bytes": "^1.0.0"
}
},
+ "node_modules/sanitize-html": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.14.0.tgz",
+ "integrity": "sha512-CafX+IUPxZshXqqRaG9ZClSlfPVjSxI0td7n07hk8QO2oO+9JDnlcL8iM8TWeOXOIBFgIOx6zioTzM53AOMn3g==",
+ "license": "MIT",
+ "dependencies": {
+ "deepmerge": "^4.2.2",
+ "escape-string-regexp": "^4.0.0",
+ "htmlparser2": "^8.0.0",
+ "is-plain-object": "^5.0.0",
+ "parse-srcset": "^1.0.2",
+ "postcss": "^8.3.11"
+ }
+ },
"node_modules/scheduler": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
diff --git a/server/package.json b/server/package.json
index 06c23f3a1e..2d3356bb2c 100644
--- a/server/package.json
+++ b/server/package.json
@@ -85,6 +85,7 @@
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
"sanitize-filename": "^1.6.3",
+ "sanitize-html": "^2.14.0",
"semver": "^7.6.2",
"sharp": "^0.33.0",
"sirv": "^3.0.0",
@@ -117,6 +118,7 @@
"@types/picomatch": "^3.0.0",
"@types/pngjs": "^6.0.5",
"@types/react": "^19.0.0",
+ "@types/sanitize-html": "^2.13.0",
"@types/semver": "^7.5.8",
"@types/supertest": "^6.0.0",
"@types/ua-parser-js": "^0.7.36",
diff --git a/server/src/services/api.service.ts b/server/src/services/api.service.ts
index a18f863f99..71fb36b4f2 100644
--- a/server/src/services/api.service.ts
+++ b/server/src/services/api.service.ts
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
import { Cron, CronExpression, Interval } from '@nestjs/schedule';
import { NextFunction, Request, Response } from 'express';
import { readFileSync } from 'node:fs';
+import sanitizeHtml from 'sanitize-html';
import { ONE_HOUR } from 'src/constants';
import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
@@ -12,21 +13,25 @@ import { VersionService } from 'src/services/version.service';
import { OpenGraphTags } from 'src/utils/misc';
const render = (index: string, meta: OpenGraphTags) => {
+ const [title, description, imageUrl] = [meta.title, meta.description, meta.imageUrl].map((item) =>
+ item ? sanitizeHtml(item, { allowedTags: [] }) : '',
+ );
+
const tags = `
-
+
-
-
- ${meta.imageUrl ? `` : ''}
+
+
+ ${imageUrl ? `` : ''}
-
-
+
+
- ${meta.imageUrl ? `` : ''}`;
+ ${imageUrl ? `` : ''}`;
return index.replace('', tags);
};