{"record":{"id":"b5d19878735d6808","repo":"DIYgod/RSSHub","slug":"invalid-domain-b5d198","errorCode":null,"errorMessage":"Invalid domain","messagePattern":"Invalid domain","errorType":"validation","errorClass":"InvalidParameterError","httpStatus":null,"severity":"error","filePath":"lib/routes/gamme/tag.ts","lineNumber":26,"sourceCode":"import { isValidHost } from '@/utils/valid-host';\n\nexport const route: Route = {\n    path: '/:domain/tag/:tag',\n    categories: ['new-media'],\n    example: '/gamme/news/tag/歐派',\n    parameters: {\n        domain: '網站，`news` 為宅宅新聞，`sexynews` 為西斯新聞',\n        tag: '標籤，可在 URL 找到',\n    },\n    name: '標籤',\n    maintainers: ['TonyRL'],\n    handler,\n};\n\nasync function handler(ctx) {\n    const { domain = 'news', tag } = ctx.req.param();\n    if (!isValidHost(domain)) {\n        throw new InvalidParameterError('Invalid domain');\n    }\n    const baseUrl = `https://${domain}.gamme.com.tw`;\n    const pageUrl = `${baseUrl}/tag/${tag}`;\n\n    const { data } = await got(pageUrl);\n    const $ = load(data);\n\n    const list = $('#category_new li a, .List-4 h3 a')\n        .toArray()\n        .map((item): DataItem => {\n            const $item = $(item);\n            return {\n                title: $item.attr('title') || $item.text(),\n                link: $item.attr('href'),\n            };\n        });\n\n    const items = await Promise.all(","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/gamme/tag.ts#L8-L44","documentation":"Identical guard to the Gamme category route: the tag route builds https://{domain}.gamme.com.tw/tag/{tag} and validates domain via isValidHost first. A failure throws InvalidParameterError('Invalid domain').","triggerScenarios":"Supplying a domain other than the two known Gamme subdomains (news, sexynews), or a malformed/empty domain string. The tag parameter itself is not validated here — only the host.","commonSituations":"Typing the full hostname or URL into the domain field; guessing subdomain names; domain parameter left set to an old value after Gamme consolidated subdomains.","solutions":["Pass only 'news' or 'sexynews' as domain.","Leave domain unset to default to 'news'.","Extend isValidHost if a new subdomain is introduced."],"exampleFix":"// before\nif (!isValidHost(domain)) {\n    throw new InvalidParameterError('Invalid domain');\n}\n\n// after\nconst validDomains = ['news', 'sexynews'];\nif (!validDomains.includes(domain)) {\n    throw new InvalidParameterError(`Invalid domain \"${domain}\". Valid: ${validDomains.join(', ')}`);\n}","handlingStrategy":"validation","validationCode":"const validDomains = ['news', 'sexynews'];\nif (!validDomains.includes(domain)) {\n  throw new InvalidParameterError(`Invalid domain. Valid: ${validDomains.join(', ')}`);\n}","typeGuard":"const isValidDomain = (d: string): d is 'news' | 'sexynews' => d === 'news' || d === 'sexynews';","tryCatchPattern":null,"preventionTips":["Whitelist subdomain labels.\nDefault to 'news'.\nValidate before URL interpolation."],"tags":["validation","user-input","url-injection"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}