{"record":{"id":"2682272c280137ed","repo":"DIYgod/RSSHub","slug":"this-rss-is-disabled-unless-allow-user-supply-uns-268227","errorCode":null,"errorMessage":"This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.","messagePattern":"This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'\\.","errorType":"exception","errorClass":"ConfigNotFoundError","httpStatus":null,"severity":"warning","filePath":"lib/routes/mastodon/timeline-local.ts","lineNumber":43,"sourceCode":"    features: {\n        requireConfig: false,\n        requirePuppeteer: false,\n        antiCrawler: false,\n        supportBT: false,\n        supportPodcast: false,\n        supportScihub: false,\n    },\n    name: 'Instance timeline (local)',\n    maintainers: ['hoilc'],\n    handler,\n    description: 'If the instance address is not `mastodon.social` or `pawoo.net`, then the route requires `ALLOW_USER_SUPPLY_UNSAFE_DOMAIN` to be `true`.',\n};\n\nasync function handler(ctx) {\n    const site = ctx.req.param('site');\n    const only_media = ctx.req.param('only_media') === 'true' ? 'true' : 'false';\n    if (!config.feature.allow_user_supply_unsafe_domain && !utils.allowSiteList.includes(site)) {\n        throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);\n    }\n\n    const url = `http://${site}/api/v1/timelines/public?local=true&only_media=${only_media}`;\n\n    const response = await got.get(url, { headers: utils.apiHeaders(site) });\n    const list = response.data;\n\n    return {\n        title: `Local Public${ctx.req.param('only_media') === 'true' ? ' Media' : ''} Timeline on ${site}`,\n        link: `https://${site}`,\n        item: utils.parseStatuses(list),\n    };\n}\n","sourceCodeStart":25,"sourceCodeEnd":57,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/mastodon/timeline-local.ts#L25-L57","documentation":"ConfigNotFoundError thrown by the Mastodon local-timeline route when :site is not allowlisted and ALLOW_USER_SUPPLY_UNSAFE_DOMAIN is false. The route then calls http://<site>/api/v1/timelines/public?local=true; the guard exists to stop RSSHub from being pointed at arbitrary hosts.","triggerScenarios":"GET /mastodon/timeline-local/:site/:only_media? where :site is not in allowSiteList and the unsafe-domain feature flag is false.","commonSituations":"Subscribing to a local timeline on a non-allowlisted instance; deploying a public RSSHub with the SSRF guard intentionally enabled; site segment malformed.","solutions":["Set ALLOW_USER_SUPPLY_UNSAFE_DOMAIN=true on trusted/private deployments.","Set MASTODON_API_HOST to your instance so it joins the allowlist.","Confirm the site is a bare hostname reachable over HTTPS.","For public deployments, keep the guard on and request an allowlist entry."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const ALLOWED = ['mastodon.social','pawoo.net','fosstodon.org', config.mastodon.apiHost].filter(Boolean);\nif (!ALLOWED.includes(site) && !config.feature.allow_user_supply_unsafe_domain) {\n    throw new ConfigNotFoundError('Instance not allowlisted; set ALLOW_USER_SUPPLY_UNSAFE_DOMAIN=true or MASTODON_API_HOST');\n}","typeGuard":"const isAllowlistedSite = (site: string): boolean =>\n    ['mastodon.social','pawoo.net','fosstodon.org', config.mastodon.apiHost].filter(Boolean).includes(site);","tryCatchPattern":null,"preventionTips":["Pre-validate the site before the timeline fetch.","Set MASTODON_API_HOST for frequently-used instances.","Leave the guard on for public instances to prevent SSRF abuse."],"tags":["mastodon","config","ssrf","config-not-found","security"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}