{"record":{"id":"8ca7c72f53894ceb","repo":"jdx/mise","slug":"unsupported-query-parameter","errorCode":null,"errorMessage":"unsupported query parameter","messagePattern":"unsupported query parameter","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/github_relay.rs","lineNumber":234,"sourceCode":"            matches!(*kind, \"refs\" | \"matching-refs\") && matches!(method, \"GET\" | \"HEAD\")\n        }\n        [\"api\", \"repos\", _, _, kind, ..] => {\n            matches!(\n                *kind,\n                \"contents\" | \"releases\" | \"tags\" | \"branches\" | \"tarball\" | \"zipball\"\n            ) && matches!(method, \"GET\" | \"HEAD\")\n        }\n        [\"web\", _, _, \"releases\", \"download\", _, ..] => matches!(method, \"GET\" | \"HEAD\"),\n        [\"web\", _, _, \"archive\", _, ..] => matches!(method, \"GET\" | \"HEAD\"),\n        _ => false,\n    };\n    if !allowed {\n        bail!(\"GitHub relay permits read-only repository operations only\");\n    }\n    if !git && let Some(query) = query {\n        for (key, _) in url::form_urlencoded::parse(query.as_bytes()) {\n            if !matches!(key.as_ref(), \"ref\" | \"page\" | \"per_page\") {\n                bail!(\"unsupported query parameter\");\n            }\n        }\n    }\n    let host = if p[0] == \"api\" {\n        \"api.github.com\"\n    } else {\n        \"github.com\"\n    };\n    let suffix = path.split_once('/').expect(\"validated path\").1;\n    let mut url = format!(\"https://{host}/{suffix}\");\n    let archive_repo = match p.as_slice() {\n        [\"api\", \"repos\", _, _, \"tarball\" | \"zipball\", ..] => Some(name.clone()),\n        [\"web\", _, _, \"archive\", rest @ ..] => {\n            let reference = rest.join(\"/\");\n            let (kind, reference) = if let Some(reference) = reference.strip_suffix(\".tar.gz\") {\n                (\"tarball\", reference)\n            } else if let Some(reference) = reference.strip_suffix(\".zip\") {\n                (\"zipball\", reference)","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/github_relay.rs#L216-L252","documentation":"For non-git requests, `authorize` parses the query string and permits only the keys `ref`, `page`, and `per_page`. Any other query parameter causes the request to be rejected, because the relay forwards only narrowly defined query shapes and must not pass arbitrary parameters upstream. Git smart-HTTP requests are exempt from this check.","triggerScenarios":"A client appends extra parameters to an API request, e.g. `/api/repos/o/r/contents?ref=main&token=x`, `?sort=name`, `?recursive=true`, or a cache-busting `?_=1234` on a web archive download.","commonSituations":"SDKs or HTTP clients that automatically add parameters (utm, cache-busters, auth tokens in query strings); tools passing sort/order/filter options the relay does not allowlist; leaked credentials embedded in query strings by misconfigured clients.","solutions":["Remove all query parameters except `ref`, `page`, and `per_page` from the request URL","If you need server-side filtering/sorting not supported by these keys, fetch unfiltered and filter client-side","Move any credentials out of query strings into headers handled by the relay"],"exampleFix":"// before\nGET /api/repos/org/repo/contents?ref=main&sort=name\n// after\nGET /api/repos/org/repo/contents?ref=main","handlingStrategy":"validation","validationCode":"fn query_is_allowed(query: Option<&str>) -> bool {\n    query.map_or(true, |q| {\n        url::form_urlencoded::parse(q.as_bytes())\n            .all(|(k, _)| matches!(k.as_ref(), \"ref\" | \"page\" | \"per_page\"))\n    })\n}","typeGuard":null,"tryCatchPattern":"match authorize(&scope, method, path, query) {\n    Err(e) if e.to_string().contains(\"unsupported query parameter\") => {\n        eprintln!(\"strip non-allowlisted query params (only ref, page, per_page)\");\n    }\n    Ok(t) => forward(t),\n    Err(e) => return Err(e),\n}","preventionTips":["Build query strings explicitly with only ref/page/per_page","Disable client features that auto-append params (cache busters, telemetry)","Keep credentials in headers, never in the query string","Filter/sort data client-side when the relay does not allowlist the parameter"],"tags":["github","relay","query-parameters","allowlist"],"backgroundTag":"invalid-query-parameter","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}