{"record":{"id":"a05065d4cd100990","repo":"DIYgod/RSSHub","slug":"invalid-subdomain","errorCode":null,"errorMessage":"Invalid subdomain","messagePattern":"Invalid subdomain","errorType":"exception","errorClass":null,"httpStatus":503,"severity":"warning","filePath":"lib/routes-deprecated/booth-pm/shop.js","lineNumber":9,"sourceCode":"const got = require('@/utils/got');\nconst cheerio = require('cheerio');\nconst { isValidHost } = require('@/utils/valid-host');\nconst maxPages = 5;\n\nmodule.exports = async (ctx) => {\n    const { subdomain } = ctx.params;\n    if (!isValidHost(subdomain)) {\n        throw new Error('Invalid subdomain');\n    }\n    const shopUrl = `https://${subdomain}.booth.pm`;\n\n    let shopName;\n    const items = [];\n    for (let page = 1; page <= maxPages; page++) {\n        const pageUrl = `${shopUrl}/items?page=${page}`;\n        // eslint-disable-next-line no-await-in-loop\n        const response = await got({\n            method: 'get',\n            url: pageUrl,\n        });\n\n        const data = response.data;\n\n        const $ = cheerio.load(data);\n        shopName = $('div.shop-name > span').text();\n        const pageItems = $('li.item');","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes-deprecated/booth-pm/shop.js#L1-L27","documentation":"Thrown by the booth-pm shop route when the `subdomain` path parameter fails isValidHost. The value is interpolated into `https://${subdomain}.booth.pm`, so it must be a single safe DNS label.","triggerScenarios":"Request to /booth/pm/shop/:subdomain with a subdomain containing dots, slashes, protocol characters, or other invalid host characters.","commonSituations":"User passes the full shop URL instead of the label; passes 'shop.booth.pm' instead of 'shop'; attempts traversal via '../'.","solutions":["Pass only the leading subdomain label (e.g. 'shop' for shop.booth.pm).","Strip any protocol or trailing path before submitting.","Confirm the shop subdomain exists on booth.pm."],"exampleFix":"// before\n/booth/pm/shop/shop.booth.pm\n// after\n/booth/pm/shop/shop","handlingStrategy":"validation","validationCode":"import { isValidHost } from '@/utils/valid-host';\nif (!isValidHost(subdomain)) throw new Error('Invalid subdomain');","typeGuard":"const isSafeSubdomain = (v: unknown): boolean =>\n  typeof v === 'string' && /^[a-z0-9-]+$/i.test(v) && !v.includes('.');","tryCatchPattern":null,"preventionTips":["Extract only the leading label from a shop URL before passing it.","Never embed full URLs or paths in host-derived parameters."],"tags":["validation","routes","ssrf-guard"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}