Skip to content

fix: stop error-code lookups resolving through Object.prototype - #1913

Merged
dinwwwh merged 4 commits into
middleapi:mainfrom
dinwwwh:claude/security-review-findings-d76326
Aug 22, 2026
Merged

fix: stop error-code lookups resolving through Object.prototype#1913
dinwwwh merged 4 commits into
middleapi:mainfrom
dinwwwh:claude/security-review-findings-d76326

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Aug 21, 2026

Copy link
Copy Markdown
Member

Error-code lookups like map[error.code] resolved codes such as toString or constructor through Object.prototype. In reconcileORPCError the resolved prototype method has no .data schema, so a crafted wire error was stamped defined/inferable with its payload never validated. This adds a getOwn helper to @orpc/shared and uses it at every error-code lookup.

Fixes

  • reconcileORPCError no longer promotes prototype-coded errors to defined; they downgrade like any unmapped code.
  • RPC and OpenAPI encodeError return the default error status for prototype-coded errors instead of an invalid status: [Function] response.
  • catchORPCErrorCodes (Effect) no longer invokes Object.prototype.toString as an error handler.
  • SmartCoercionLinkPlugin no longer probes prototype members when looking up error data schemas.
  • createORPCErrorConstructorMap constructors treat prototype-named codes as undefined config.

Testing

  • One regression test per changed source file (fails without the guard), plus unit tests for getOwn.
  • pnpm lint, pnpm type:check, and affected package tests (182 files, 2070 tests) pass.

A wire error coded like 'toString' resolved map[error.code] to
Object.prototype methods. In reconcileORPCError the resolved value has
no .data schema, so the error was stamped defined/inferable with its
payload never validated. Sibling lookups in the error constructor map,
RPC/OpenAPI errorStatusMap, Effect catchORPCErrorCodes, and the smart
coercion link plugin had the same prototype hole.

Adds getOwn to @orpc/shared and uses it at every error-code lookup.
@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
orpc Ready Ready Preview Aug 22, 2026 2:41am

@pkg-pr-new

pkg-pr-new Bot commented Aug 21, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@1913

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@1913

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@1913

@orpc/client

npm i https://pkg.pr.new/@orpc/client@1913

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@1913

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@1913

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@1913

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@1913

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@1913

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@1913

@orpc/experimental-msw

npm i https://pkg.pr.new/@orpc/experimental-msw@1913

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@1913

@orpc/next

npm i https://pkg.pr.new/@orpc/next@1913

@orpc/node

npm i https://pkg.pr.new/@orpc/node@1913

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@1913

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@1913

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@1913

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@1913

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@1913

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@1913

@orpc/server

npm i https://pkg.pr.new/@orpc/server@1913

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@1913

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@1913

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@1913

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@1913

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@1913

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@1913

commit: 700eb9b

@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing dinwwwh:claude/security-review-findings-d76326 (700eb9b) with main (519c3f2)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (3078b1c) during the generation of this report, so 519c3f2 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ One regression test cannot fail without its guard — minor.

Reviewed changes

  • getOwn helper (@orpc/shared): new Object.hasOwn-based property read returning undefined for inherited keys like toString, with targeted unit tests.
  • Error-code lookups hardened at five sites: reconcileORPCError, createORPCErrorConstructorMap, Effect catchORPCErrorCodes, and both RPC/OpenAPI handler codec status maps now use getOwn(map, code) instead of map[code], so prototype-coded wire errors downgrade to unmapped instead of being promoted to defined/inferable, receiving status: [Function], or invoking Object.prototype methods as handlers.

I verified the exploit claims empirically by temporarily reverting each source guard and re-running the corresponding test: all five functional guards fail their regression tests when reverted (e.g. encodeError returns [Function toString] as the status; catchORPCErrorCodes dies with Not a valid effect: [object Object]) and pass with the fix. The new getOwn unit tests and the reconciliation downgrade path are sound. One test does not pin anything — see the inline comment.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread packages/json-schema/src/smart-coercion-link-plugin.test.ts Outdated
Object.prototype members never carry a .data property, so the smart
coercion interceptor rethrows the original error with or without the
getOwn guard; the test passed either way and pinned nothing.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Dropped the unfalsifiable does not resolve error codes through Object.prototype regression test from smart-coercion-link-plugin.test.ts — it passed with or without the getOwn guard (no Object.prototype member carries .data), so it pinned nothing. The prior review thread was resolved, and the getOwn lookup at smart-coercion-link-plugin.ts:71 stays for consistency with the other five hardened sites.

Verified the file still has all 5 original tests passing (pnpm vitest run packages/json-schema/src/smart-coercion-link-plugin.test.ts). Nothing in the incremental delta raises new concerns; the remaining five regression tests each fail without their guard as established in the prior review.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

…named codes

Intent assertion for the smart coercion error path: a defined error
coded like 'toString' must be rethrown untouched. It cannot distinguish
the getOwn guard today (no Object.prototype member carries .data), but
it protects this path against future refactors.
@dinwwwh
dinwwwh merged commit 0b4ddd3 into middleapi:main Aug 22, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant