T09 · Insecure Skill Coding Practices
- Location
scripts/run-mog-rating-preview.mjs:26- Finding
Unrestricted Base URL Allows Sensitive Image Uploads to Attacker-Controlled Origins
- Content
View full analysis
Vulnerability Details
File Location:
scripts/run-mog-rating-preview.mjs:26-43, 67-71, 191-227;SKILL.md:13-15
Vulnerability Type: Unvalidated destination URL for sensitive file uploads
Risk Level: HighVulnerable Code
js export function parseArgs(argv = process.argv.slice(2), env = process.env) { const options = { baseUrl: env.MOGSCORE_BASE_URL?.trim() || DEFAULT_BASE_URL, browserExecutable: env.MOGSCORE_BROWSER_EXECUTABLE?.trim() || "", headed: true, image: "", timeoutMs: DEFAULT_TIMEOUT_MS }; for (let index = 0; index < argv.length; index += 1) { const arg = argv[index]; if (arg === "--headed") { options.headed = true; continue; } if (arg === "--image" || arg === "--base-url" || arg === "--browser-executable" || arg === "--timeout-ms") { const value = argv[index + 1]; if (!value || value.startsWith("--")) { throw new UsageError(`${arg} requires a value.`); } index += 1; if (arg === "--image") { options.image = value; } else if (arg === "--base-url") { options.baseUrl = value; }js export function buildTargetUrl(baseUrl) { const origin = new URL(baseUrl).origin; const target = new URL("/mog-rating", origin); target.searchParams.set("mode", "upload"); return target.toString(); }js export async function runMogRatingPreview(options) { const imagePath = path.resolve(options.image); const targetUrl = buildTargetUrl(options.baseUrl); try { await fs.access(imagePath); } catch { return buildErrorPayload("upload_failed", `Image file is not readable: ${imagePath}`, false); } let browser; try { const executablePath = await resolveBrowserExecutable(options); const { chromium } = await import("playwright-core"); browser = await chromium.launch(buildBrowserL ...[truncated 4057 chars]- Remediation
View remediation
Remediation Suggestions
- Remove
MOGSCORE_BASE_URLand--base-urlif alternate service origins are not essential. - Otherwise, validate the URL against an explicit allowlist before launching the browser:
- Require the
https:scheme. - Require the exact hostname
mogscore.ai, or a narrowly defined list of approved subdomains. - Reject embedded usernames and passwords.
- Reject unexpected ports.
- Normalize the hostname before comparison.
- Require the
- After
page.goto(), inspectpage.url()and abort unless the final origin remains on the approved allowlist. Apply the same check after any later navigation. - Update
isReportsResponse()to verify the response origin in addition to the HTTP method and pathname. - Validate that
--imagepoints to a regular file with an approved image extension and detected MIME type before attaching it. - Display or log the validated upload origin before transferring the image so that the destination is auditable.
- Add tests covering HTTP URLs, deceptive hostnames, embedded credentials, nonstandard ports, cross-origin redirects, and report responses from unrelated origins.
- Remove
