CVE-2024-27926 (published 2024-03-21T02:52Z)

RSSHub is an open source RSS feed generator. Starting in version 1.0.0-master.cbbd829 and prior to version 1.0.0-master.d8ca915, ahen the specially crafted image is supplied to the internal media proxy, it proxies the image without handling XSS vulnerabilities, allowing for the execution of arbitrary JavaScript code. Users who access the deliberately constructed URL are affected. This vulnerability was fixed in version 1.0.0-master.d8ca915. No known workarounds are available.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/DIYgod/RSSHub
commit_details: repo_url: https://github.com/DIYgod/RSSHub
author: DIYgod
author_date: 2024-03-04 23:06:41+08:00
msg: feat: remove MEDIA_PROXY_KEY and internal media proxy
repository: repo_url: https://github.com/DIYgod/RSSHub
repo_name: DIYgod/RSSHub
description: 🧡 Everything is RSSible
repo_language: TypeScript
owner: DIYgod
file_changes: filename: config.ts
change_type: ModificationType.MODIFY
diff: @@ -61,7 +61,6 @@ export type Config = {
         allow_user_hotlink_template: boolean;
         filter_regex_engine: string;
         allow_user_supply_unsafe_domain: boolean;
-        mediaProxyKey?: string;
     };
     suffix?: string;
     titleLengthLimit: number;
@@ -391,7 +390,6 @@ const calculateValue = () => {
             allow_user_hotlink_template: toBoolean(envs.ALLOW_USER_HOTLINK_TEMPLATE, false),
             filter_regex_engine: envs.FILTER_REGEX_ENGINE || 're2',
             allow_user_supply_unsafe_domain: toBoolean(envs.ALLOW_USER_SUPPLY_UNSAFE_DOMAIN, false),
-            mediaProxyKey: envs.MEDIA_PROXY_KEY,
         },
         suffix: envs.SUFFIX,
         titleLengthLimit: toInt(envs.TITLE_LENGTH_LIMIT, 150),

programming_language: TypeScript
filename: maintainer.ts
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,4 @@
 export default {
-    '/m/:key/:url': ['TonyRL'],
     '/routes/:lang?': ['DIYgod'],
     '/transform/html/:url/:routeParams': ['ttttmr'],
     '/transform/json/:url/:routeParams': ['ttttmr'],

programming_language: TypeScript
filename: media.ts
change_type: ModificationType.DELETE
diff: @@ -1,52 +0,0 @@
-// @ts-nocheck
-import got from '@/utils/got';
-import { config } from '@/config';
-const { getDomain } = require('tldts');
-const { refererMap } = require('./referer-map');
-
-export default async (ctx) => {
-    if (!config.feature.mediaProxyKey) {
-        throw new Error('Internal media proxy is disabled.');
-    }
-
-    const key = ctx.req.param('key');
-    if (key !== config.feature.mediaProxyKey) {
-        throw new Error('Invalid media proxy key.');
-    }
-
-    const url = decodeURIComponent(ctx.req.param('url'));
-    const requestUrl = new URL(url);
-    const { hostname, origin } = requestUrl;
-
-    const domain = getDomain(hostname);
-
-    let referer = refererMap.get(domain);
-    referer ||= origin;
-
-    const { headers } = await got.head(url, {
-        headers: {
-            referer,
-        },
-    });
-
-    const cacheControl = headers['cache-control'];
-    const contentType = headers['content-type'];
-    const contentLength = headers['content-length'];
-
-    if (!contentType.startsWith('image/') || headers.server === 'RSSHub') {
-        return ctx.redirect(url);
-    }
-
-    ctx.set({
-        'cache-control': cacheControl || `public, max-age=${config.cache.contentExpire}`,
-        'content-length': contentLength,
-        'content-type': contentType,
-        server: 'RSSHub',
-    });
-
-    ctx.body = await got.stream(url, {
-        headers: {
-            referer,
-        },
-    });
-};

programming_language: unknown
filename: router.ts
change_type: ModificationType.MODIFY
diff: @@ -1,5 +1,4 @@
 export default (router) => {
-    router.get('/m/:key/:url', './media');
     router.get('/routes/:lang?', './routes');
     router.get('/transform/html/:url/:routeParams', './transform/html');
     router.get('/transform/json/:url/:routeParams', './transform/json');

programming_language: TypeScript
filename: channel.ts
change_type: ModificationType.MODIFY
diff: @@ -55,7 +55,7 @@ const mediaTagDict = {
 };
 
 export default async (ctx) => {
-    const useWeb = ctx.req.param('routeParams') || !(config.telegram.session && config.feature.mediaProxyKey);
+    const useWeb = ctx.req.param('routeParams') || !config.telegram.session;
     if (!useWeb) {
         return require('./tglib/channel').default(ctx);
     }

programming_language: TypeScript
filename: channel.ts
change_type: ModificationType.MODIFY
diff: @@ -33,10 +33,6 @@ function parseRange(range, length) {
 }
 
 async function getMedia(ctx) {
-    if (ctx.req.param('key') !== config.feature.mediaProxyKey) {
-        throw new Error('Invalid key');
-    }
-
     const media = await decodeMedia(ctx.req.param('username'), ctx.req.param('media'));
     if (!media) {
         ctx.status = 500;

programming_language: JavaScript
filename: client.ts
change_type: ModificationType.MODIFY
diff: @@ -69,7 +69,7 @@ function ExpandInlineBytes(bytes) {
 }
 
 function getMediaLink(ctx, channel, channelName, message) {
-    const base = `${ctx.protocol}://${ctx.host}/telegram/channel/${channelName}/${config.feature.mediaProxyKey}/`;
+    const base = `${ctx.protocol}://${ctx.host}/telegram/channel/${channelName}`;
     const src = base + `${channel.channelId}_${message.id}`;
 
     const x = message.media;

programming_language: JavaScript
filename: timeline.ts
change_type: ModificationType.MODIFY
diff: @@ -145,7 +145,7 @@ export default async (ctx) => {
                 'Content-Type': 'text/html; charset=UTF-8',
                 'Cache-Control': 'no-cache',
             });
-            ctx.body = `<script>window.location = '/weibo/timeline/${uid}${routeParams ? `/${routeParams}` : ''}'</script>`;
+            ctx.html(`<script>window.location = '/weibo/timeline/${uid}${routeParams ? `/${routeParams}` : ''}'</script>`);
         }
     } else {
         const { app_key = '', redirect_url = ctx.req.origin + '/weibo/timeline/0' } = config.weibo;

programming_language: TypeScript
filename: config.md
change_type: ModificationType.MODIFY
diff: @@ -198,8 +198,6 @@ Configs in this sections are in beta stage, and **are turn off by default**. Ple
 
 `ALLOW_USER_SUPPLY_UNSAFE_DOMAIN`: allow users to provide a domain as a parameter to routes that are not in their allow list, respectively. Public instances are suggested to leave this value default, as it may lead to [Server-Side Request Forgery (SSRF)](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery)
 
-`MEDIA_PROXY_KEY`: the access key for internal media proxy.
-
 ## Other Application Configurations
 
 `DISALLOW_ROBOT`: prevent indexing by search engine, default to enable, set false or 0 to disable

programming_language: Markdown
filename: other.mdx
change_type: ModificationType.MODIFY
diff: @@ -121,7 +121,7 @@ See [#app-store-mac-app-store](/routes/program-update#app-store-mac-app-store)
 
 <Route author="DIYgod" example="/scmp/coronavirus" path="/scmp/coronavirus" />
 
-### Macao Pagina Electrónica Especial Contra Epidemias: What’s New {#corona-virus-disease-2019-macao-pagina-electr%C3%B3nica-especial-contra-epidemias-what-s-new}
+### Macao Pagina Electrónica Especial Contra Epidemias: What’s New {#corona-virus-disease-2019-macao-pagina-electronica-especial-contra-epidemias-what-s-new}
 
 Official Website: [https://www.ssm.gov.mo/apps1/PreventWuhanInfection/en.aspx](https://www.ssm.gov.mo/apps1/PreventWuhanInfection/en.aspx)
 
@@ -442,10 +442,6 @@ It is recommended to use with clipping tools such as Notion Web Clipper.
 
 ## RSSHub {#rsshub}
 
-### Internal Media Proxy {#rsshub-internal-media-proxy}
-
-<Route author="TonyRL" example="/rsshub/m/key/https%3A%2F%2Fdocs.rsshub.app%2Fimg%2Flogo.png" path="/rsshub/m/:key/:url" paramsDesc={['Media Proxy Key', '`encodeURIComponent`ed URL address']} configRequired="1" />
-
 ### Transformation - HTML {#rsshub-transformation-html}
 
 Pass URL and transformation rules to convert HTML/JSON into RSS.

programming_language: Markdown
filename: social-media.mdx
change_type: ModificationType.MODIFY
diff: @@ -784,7 +784,7 @@ If the instance address is not `mastodon.social` or `pawoo.net`, then the route
 <Route author="synchrone" example="/telegram/channel/telegram" path="/telegram/channel/:username" paramsDesc={['Channel name, without @']} configRequired="1" />
 
 :::warning
-This route requires user-based `TELEGRAM_SESSION` which can be acquired and `MEDIA_PROXY_KEY`.
+This route requires user-based `TELEGRAM_SESSION`.
 :::
 
 ### Sticker Pack {#telegram-sticker-pack}

programming_language: Markdown
filename: config.md
change_type: ModificationType.MODIFY
diff: @@ -196,8 +196,6 @@ RSSHub 支持使用访问密钥 / 码进行访问控制。开启将会激活全
 
 `ALLOW_USER_SUPPLY_UNSAFE_DOMAIN`: 允许用户为路由提供域名作为参数。建议公共实例不要调整此选项，开启后可能会导致 [服务端请求伪造（SSRF）](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery)
 
-`MEDIA_PROXY_KEY`: 内置多媒体代理的访问密钥
-
 ## 其他应用配置
 
 `DISALLOW_ROBOT`: 阻止搜索引擎收录，默认开启，设置 false 或 0 关闭

programming_language: Markdown