Repository navigation
fix(sse): keep a model name from rewriting the upstream URL path - #15067
Merged
diegosouzapw merged 2 commits intoSep 29, 2026
Merged
diegosouzapw merged 2 commits into
diegosouzapw merged 2 commits into
Conversation
Many providers put the model id into the upstream URL path
(`.../models/{id}:generateContent`, `.../deployments/{id}/...`). The model
name comes from the request, and parseModel only rejected a literal `../`
or a backslash-dot pair. The URL parser that fetch uses folds `%2e%2e` into
a dot-segment, ends the path at `#` and starts a query at `?`, so
`gemini/%2e%2e/cachedContents#` made the executor POST to
`/v1beta/cachedContents` and `gemini/.%2e/.%2e/upload/v1beta/files?x=` to
`/upload/v1beta/files`, with the operator's key attached. The same string
reaches Vertex's project-scoped paths with the service-account token.
It also defeats a per-key model allow-list: a key limited to
`gemini/gemini-2.5-flash*` matched
`gemini/gemini-2.5-flash/%2e%2e/gemini-3-pro`, which resolves to
`models/gemini-3-pro`. A catalog that is not marked authoritative for the
provider does not stop it, since an unknown id is only refused when the
catalog is.
Refuse, in parseModel and in every registry parser (image, embedding,
rerank, moderation, OCR, video, music, upscale and the three audio ones),
an id that has a query or fragment delimiter, a backslash, a percent-encoded
dot, slash, backslash, `#`, `?` or NUL, or a `.` / `..` path segment. Slashes,
colons, `@`, brackets and dots inside names are unchanged; none of the 3,673
model ids in the built-in catalogs is affected.
Signed-off-by: Minxi Hou <houminxi@gmail.com>
no-explicit-any is an error under tests/, so the new model-id test failed lint.
diegosouzapw
merged commit Sep 29, 2026
2611af3
into
cheaper-inference:release/v3.8.51
11 of 16 checks passed
diegosouzapw
added a commit
that referenced
this pull request
Sep 29, 2026
… 4) (#15109) Release-captain base-red fix (v3.8.51 release PR #11442, unit shards 3-4): one production defect (proxyLogger pulled into every settings→proxies import and queried the DB at import time; helper extracted to src/lib/proxyLogHost.ts) and seven contract propagations from #14732, #15044, #15067, #13548, #14117×#14844, #12810. 74/74 across the seven files, 176/176 proxy-log neighbours, typecheck clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Many providers put the model id into the upstream URL path (
.../models/{id}:generateContent,.../deployments/{id}/...). The model name comes from the request, andparseModelonly rejected a literal../or a backslash-dot pair. The URL parser that fetch uses folds%2e%2einto a dot-segment, ends the path at#and starts a query at?, sogemini/%2e%2e/cachedContents#made the executor POST to/v1beta/cachedContentsandgemini/.%2e/.%2e/upload/v1beta/files?x=to/upload/v1beta/files, with the operator's key attached. The same string reaches Vertex's project-scoped paths with the service-account token. It also defeats a per-key model allow-list: a key limited togemini/gemini-2.5-flash*matchedgemini/gemini-2.5-flash/%2e%2e/gemini-3-pro, which resolves tomodels/gemini-3-pro. A catalog that is not marked authoritative for the provider does not stop it, since an unknown id is only refused when the catalog is.Refuse, in
parseModeland in every registry parser (image, embedding, rerank, moderation, OCR, video, music, upscale and the three audio ones), an id that has a query or fragment delimiter, a backslash, a percent-encoded dot, slash, backslash,#,?or NUL, or a./..path segment. Slashes, colons,@, brackets and dots inside names are unchanged; none of the 3,673 model ids in the built-in catalogs is affected.Related Issues
Validation
npm run typecheck:corenpm run linton the changed files (Prettier and ESLint clean)release/v3.8.51atb27c254430); focused checks rerun afterwardEach new test was run against the change reverted (it fails) and restored (it passes).
Tests Added Or Updated
tests/unit/model-id-path-injection.test.tsCoverage Notes
The listed test exercises every changed production path: the helper on unsafe and ordinary ids,
parseModel, all eleven registry parsers, and the Gemini upstream URL built from the parse result.Reviewer Notes
Five tests in that run fail on the current tip with and without this change (
tests/unit/models-catalog-low-noise-flag.test.tsx3,tests/unit/suffix-effort-propagation.test.tsx2). Voice ids already have their own validators; this closes the same class for model ids. The Codex/v1/responses/*sub-path can still carry an encoded slash (..%2f) to the upstream literally; dot-segments there are already removed by URL normalisation, so I left it.Maintainer rework (merge-batch 2026-09-28 (release drain))
new (DefaultExecutor as any)(...);no-explicit-anyis an error undertests/, so the stand-in is typed now. No production change.PROVIDER_MODELSagainsthasUnsafeModelIdSyntax: none is flagged.