DIYgod/RSSHub · error · ConfigNotFoundError
This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN
Error message
This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.
What it means
Thrown by the lemmy route handler as ConfigNotFoundError when the instance hostname extracted from the community param is not in the allowedDomain list ({lemmy.world, lemm.ee, lemmy.ml, sh.itjust.works, feddit.de, hexbear.net, beehaw.org, lemmynsfw.com, lemmy.ca, programming.dev}) and config.feature.allow_user_supply_unsafe_domain is falsy. This is the same SSRF-guard pattern as javdb: the route issues API calls to a user-influenced host, so only trusted instances are reachable by default.
Source
Thrown at lib/routes/lemmy/index.ts:73
supportPodcast: false,
supportScihub: false,
},
name: 'Community',
maintainers: ['wb14123', 'pseudoyu'],
handler,
};
async function handler(ctx) {
const sort = ctx.req.param('sort') ?? 'Active';
const community = ctx.req.param('community');
const communitySlices = community.split('@');
if (communitySlices.length !== 2) {
throw new InvalidParameterError(`Invalid community: ${community}`);
}
const instance = community.split('@', 2)[1];
const allowedDomain = ['lemmy.world', 'lemm.ee', 'lemmy.ml', 'sh.itjust.works', 'feddit.de', 'hexbear.net', 'beehaw.org', 'lemmynsfw.com', 'lemmy.ca', 'programming.dev'];
if (!config.feature.allow_user_supply_unsafe_domain && !allowedDomain.includes(new URL(`http://${instance}/`).hostname)) {
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const communityUrl = `https://${instance}/api/v3/community?name=${community}`;
const communityData = await cache.tryGet(communityUrl, async () => {
const result = await got({ method: 'get', url: communityUrl, headers: { 'Content-Type': 'application/json' } });
return result.data.community_view.community;
});
const postUrl = `https://${instance}/api/v3/post/list?type_=All&sort=${sort}&community_name=${community}&limit=50`;
const postData = await cache.tryGet(
postUrl,
async () => {
const result = await got({ method: 'get', url: postUrl, headers: { 'Content-Type': 'application/json' } });
return result.data;
},
config.cache.routeExpire,
false
);View on GitHub (pinned to bed535e087)
Solutions
- Use one of the allow-listed instances (lemmy.world, lemmey.ml, programming.dev, etc.)
- For a trusted instance you run, add its hostname to allowedDomain in lib/routes/lemmy/index.ts:69
- Set ALLOW_USER_SUPPLY_UNSAFE_DOMAIN=true in config only if you accept the SSRF risk
- Note the instance check uses exact hostname match — subdomains (e.g. ml.lemmy.world) are rejected
Example fix
// before const allowedDomain = ['lemmy.world', 'lemm.ee', 'lemmy.ml', 'sh.itjust.works', 'feddit.de', 'hexbear.net', 'beehaw.org', 'lemmynsfw.com', 'lemmy.ca', 'programming.dev']; // after — add your trusted instance const allowedDomain = ['lemmy.world', 'lemm.ee', 'lemmy.ml', 'sh.itjust.works', 'feddit.de', 'hexbear.net', 'beehaw.org', 'lemmynsfw.com', 'lemmy.ca', 'programming.dev', 'discuss.tchncs.de'];
Defensive patterns
Strategy: validation
Validate before calling
import config from '@/utils/config';
const ALLOWED = new Set(['lemmy.world', 'lemm.ee', 'lemmy.ml', 'sh.itjust.works', 'feddit.de', 'hexbear.net', 'beehaw.org', 'lemmynsfw.com', 'lemmy.ca', 'programming.dev']);
function assertAllowedInstance(instance: string): void {
const host = new URL(`http://${instance}/`).hostname;
if (!config.feature.allow_user_supply_unsafe_domain && !ALLOWED.has(host)) {
throw new ConfigNotFoundError(`instance '${host}' not allowed`);
}
} Type guard
const ALLOWED = new Set(['lemmy.world', 'lemm.ee', 'lemmy.ml', 'sh.itjust.works', 'feddit.de', 'hexbear.net', 'beehaw.org', 'lemmynsfw.com', 'lemmy.ca', 'programming.dev']);
function isAllowedLemmyInstance(instance: string): boolean {
return ALLOWED.has(new URL(`http://${instance}/`).hostname);
} Try / catch
// validate before any API call
const { instance } = parseCommunity(community);
if (!isAllowedLemmyInstance(instance) && !config.feature.allow_user_supply_unsafe_domain) {
return ctx.json({ error: 'instance not allowed', allowed: [...ALLOWED] }, 400);
}
try { return await handler(ctx); }
catch (e) { if (e instanceof ConfigNotFoundError) return ctx.json({ error: e.message }, 403); throw e; } Prevention
- Whitelist exact hostnames; subdomains are not auto-allowed
- Make the allow-list a shared constant referenced by route + tests
- Gating the feature flag is an operator-level SSRF decision — document it
- Reject before issuing any request to the user-influenced host
When it happens
Trigger: Request like /lemmy/<name>@<untrusted-instance>/Hot where the instance is not in allowedDomain and the feature flag is off. The handler builds `new URL(http://<instance>/)` and checks hostname membership; failure throws.
Common situations: User points at a smaller/newer Lemmy instance not in the allow-list; self-hoster without ALLOW_USER_SUPPLY_UNSAFE_DOMAIN; attempt to use the route as a server-side request proxy to an internal host.
Related errors
- This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN
- This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN
- This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN
- This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN
- This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/88bc93995dd189f9.
Report an issue: GitHub.