From d867d8adbb373f61c4ef502e85a7934674bb26c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 20 Jan 2026 20:50:04 -0500 Subject: [PATCH] fix: closes #10682, strip unicode control chars that explode rss module --- src/routes/feeds.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/routes/feeds.js b/src/routes/feeds.js index 18a780b4ef..3d680fe85f 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -61,6 +61,11 @@ async function validateTokenIfRequiresLogin(requiresLogin, cid, req, res) { return true; } +function stripUnicodeControlChars(str) { + // eslint-disable-next-line no-control-regex + return str.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, ''); +} + async function generateForTopic(req, res, next) { if (meta.config['feeds:disableRSS']) { return next(); @@ -80,20 +85,21 @@ async function generateForTopic(req, res, next) { if (await validateTokenIfRequiresLogin(!userPrivileges['topics:read'], topic.cid, req, res)) { const topicData = await topics.getTopicWithPosts(topic, `tid:${tid}:posts`, req.uid || req.query.uid || 0, 0, 24, true); + const mainPost = topicData.posts[0]; topics.modifyPostsByPrivilege(topicData, userPrivileges); - + const title = stripUnicodeControlChars(topicData.title); const feed = new rss({ - title: utils.stripHTMLTags(topicData.title, utils.tags), - description: topicData.posts.length ? topicData.posts[0].content : '', + title: utils.stripHTMLTags(title, utils.tags), + description: topicData.posts.length ? stripUnicodeControlChars(mainPost.content) : '', feed_url: `${nconf.get('url')}/topic/${tid}.rss`, site_url: `${nconf.get('url')}/topic/${topicData.slug}`, - image_url: topicData.posts.length ? topicData.posts[0].picture : '', - author: topicData.posts.length ? topicData.posts[0].username : '', + image_url: topicData.posts.length ? mainPost.picture : '', + author: topicData.posts.length ? mainPost.username : '', ttl: 60, }); if (topicData.posts.length > 0) { - feed.pubDate = new Date(parseInt(topicData.posts[0].timestamp, 10)).toUTCString(); + feed.pubDate = new Date(parseInt(mainPost.timestamp, 10)).toUTCString(); } const replies = topicData.posts.slice(1); replies.forEach((postData) => { @@ -103,8 +109,8 @@ async function generateForTopic(req, res, next) { ).toUTCString(); feed.item({ - title: `Reply to ${utils.stripHTMLTags(topicData.title, utils.tags)} on ${dateStamp}`, - description: postData.content, + title: `Reply to ${utils.stripHTMLTags(title, utils.tags)} on ${dateStamp}`, + description: stripUnicodeControlChars(postData.content), url: `${nconf.get('url')}/post/${postData.pid}`, author: postData.user ? postData.user.username : '', date: dateStamp,