fix(ai): harden getMediaTypeFromUrl against prototype-property collision#14751
Merged
lgrammel merged 3 commits intoApr 27, 2026
Merged
Conversation
4 tasks
lgrammel
reviewed
Apr 27, 2026
Comment on lines
+745
to
+747
| // Use `Object.hasOwn` instead of `in` so attacker-controlled extensions | ||
| // like `constructor` cannot resolve to inherited `Object.prototype` | ||
| // members and leak a non-string value through this `: string` helper. |
Collaborator
There was a problem hiding this comment.
comment not needed (there is a regression test)
lgrammel
approved these changes
Apr 27, 2026
Collaborator
|
Leaving to @felixarntz to confirm since he added the code. |
etairl
added a commit
to etairl/ai
that referenced
this pull request
Apr 27, 2026
Per review on vercel#14751: the regression test for the prototype-property collision case is enough; the inline comment is redundant. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Collaborator
|
@etairl can you reopen with signed commits? |
Contributor
Author
Sure, will do in a few hours. |
felixarntz
reviewed
Apr 27, 2026
felixarntz
left a comment
Collaborator
There was a problem hiding this comment.
@etairl Thank you for opening the PR!
We have many cases of prop in obj in our codebase - how much of a concern is this really? If it is a concern, we should probably revisit the other places too. If not, then changing it here seems a bit arbitrary.
felixarntz
approved these changes
Apr 27, 2026
…ions `getMediaTypeFromUrl` (used to infer media types for `file-url` / `image-url` parts) used `ext in URL_EXTENSION_TO_MEDIA_TYPE` against a plain object literal. A URL ending in `.constructor` therefore resolved through the prototype chain and returned the `Object` constructor function, violating the helper's `: string` return type and forwarding a non-string value to provider adapters. Switch to `Object.hasOwn(...)` so attacker-controlled extensions like `.constructor` cannot resolve to inherited `Object.prototype` keys. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per review on vercel#14751: the regression test for the prototype-property collision case is enough; the inline comment is redundant. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
7d131c5 to
bc4694e
Compare
Contributor
Author
5 tasks
gr2m
pushed a commit
that referenced
this pull request
Jun 5, 2026
…ion (#14751) ## Background `getMediaTypeFromUrl` in `convert-to-language-model-prompt.ts` does an `ext in URL_EXTENSION_TO_MEDIA_TYPE` check on a plain object literal. Because plain objects inherit from `Object.prototype`, the `in` operator returns `true` for inherited keys like `constructor`, `toString`, `hasOwnProperty`, etc. A URL ending in `.constructor` (or any other `Object.prototype` member) therefore takes the lookup branch and returns the inherited value — for `.constructor`, that's the `Object` constructor function, which is then forwarded as `mediaType` to provider adapters. This is a low-severity correctness/typing bug rather than an exploit path, but it's worth fixing: the helper's return type is `string | undefined` and a non-string slipping through can break downstream code paths that assume a string `mediaType`. Splitting this out per maintainer feedback on #14749 that the media-type fix should be its own PR. ## Summary - `packages/ai/src/prompt/convert-to-language-model-prompt.ts`: replace `ext in URL_EXTENSION_TO_MEDIA_TYPE` with `Object.hasOwn(URL_EXTENSION_TO_MEDIA_TYPE, ext)` so only own-property extensions are matched. - `packages/ai/src/prompt/convert-to-language-model-prompt.test.ts`: regression test for a URL ending in `.constructor` — asserts the helper falls back to the no-extension behaviour instead of returning a non-string value from the prototype chain. - Patch changeset. The change is one line of production code; the table is treated as a closed lookup, which is what the original code intended. ## Manual Verification - `pnpm --filter ai test:node -- src/prompt/convert-to-language-model-prompt.test.ts` — passes, including the new prototype-collision regression test. ## Checklist - [x] Tests have been added / updated (for bug fixes / features) - [ ] Documentation has been added / updated (for bug fixes / features) - [x] A _patch_ changeset for relevant packages has been added (for bug fixes / features - run `pnpm changeset` in the project root) - [x] I have reviewed this pull request (self-review) No documentation change — `getMediaTypeFromUrl` is internal. ## Future Work None. If other helpers in the prompt layer use `in` against plain object literals indexed by user input, the same prototype-confusion fix would apply, but I didn't spot any others while looking at this one. ## Related Issues - Split out from #14749 (closed) per maintainer feedback. --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Lars Grammel <lars.grammel@gmail.com>
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.
Background
getMediaTypeFromUrlinconvert-to-language-model-prompt.tsdoes anext in URL_EXTENSION_TO_MEDIA_TYPEcheck on a plain object literal. Because plain objects inherit fromObject.prototype, theinoperator returnstruefor inherited keys likeconstructor,toString,hasOwnProperty, etc. A URL ending in.constructor(or any otherObject.prototypemember) therefore takes the lookup branch and returns the inherited value — for.constructor, that's theObjectconstructor function, which is then forwarded asmediaTypeto provider adapters.This is a low-severity correctness/typing bug rather than an exploit path, but it's worth fixing: the helper's return type is
string | undefinedand a non-string slipping through can break downstream code paths that assume a stringmediaType.Splitting this out per maintainer feedback on #14749 that the media-type fix should be its own PR.
Summary
packages/ai/src/prompt/convert-to-language-model-prompt.ts: replaceext in URL_EXTENSION_TO_MEDIA_TYPEwithObject.hasOwn(URL_EXTENSION_TO_MEDIA_TYPE, ext)so only own-property extensions are matched.packages/ai/src/prompt/convert-to-language-model-prompt.test.ts: regression test for a URL ending in.constructor— asserts the helper falls back to the no-extension behaviour instead of returning a non-string value from the prototype chain.The change is one line of production code; the table is treated as a closed lookup, which is what the original code intended.
Manual Verification
pnpm --filter ai test:node -- src/prompt/convert-to-language-model-prompt.test.ts— passes, including the new prototype-collision regression test.Checklist
pnpm changesetin the project root)No documentation change —
getMediaTypeFromUrlis internal.Future Work
None. If other helpers in the prompt layer use
inagainst plain object literals indexed by user input, the same prototype-confusion fix would apply, but I didn't spot any others while looking at this one.Related Issues