镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Built-in properties cannot be accessed using Reflect, when Proxy is passed as vm context #7458

Description

@psrok1

Associated with #6158
Empty Proxy object correctly handles this case, but unfortunately it's impossible to access 'built-in' from custom getter (using Reflect)

var assert = require('assert');
var vm = require("vm");

var code = "String.prototype.f = function(){}; ''.f()";

// Test 1
assert.strictEqual(
    typeof vm.runInNewContext("String", 
            new Proxy({},{})), 
    'function');

// Test 2
assert.strictEqual(
    typeof vm.runInNewContext("String", 
            new Proxy({},{
                get: function(target, property, receiver) {
                    return Reflect.get(target, property);
                }
            })), 
    'function');

Second test returns AssertionError: 'undefined' === 'function'

Activity

  1. added
    vmIssues and PRs related to the vm subsystem.
    on Jun 28, 2016
  2. fhinkel commented on Jul 27, 2016

    @fhinkel
    Contributor

    I'm not sure I'd expect that to work, since target is {}. I'd run

    // Test 2
    assert.strictEqual(
      typeof vm.runInNewContext("String",
        new Proxy({},{
          get: function(target, property, receiver) {
            return Reflect.get(global, property);
          }
        })),
      'function');
  3. RoboPhred commented on Nov 4, 2016

    @RoboPhred

    The workaround does not make use of the new context, but simply forwards the current one. This breaks the sandboxing. For example:

    assert.strictNotEqual(
      vm.runInNewContext("String.foo = 42",
        new Proxy({},{
          get: function(target, property, receiver) {
            return Reflect.get(global, property);
          }
        })),
      String.foo);
    
  4. doughsay commented on Jun 2, 2017

    @doughsay

    Was hoping this might be fixed in Node 8.0.0, but looks like it's still an issue:

    > vm.runInNewContext("String", {})
    [Function: String]
    > vm.runInNewContext("String", new Proxy({},{}))
    [Function: String]
    > vm.runInNewContext("String", new Proxy({},{get: function(target, property) { return target[property] }}))
    undefined
    > vm.runInNewContext("String", new Proxy({},{get: function(target, property) { return Reflect.get(target, property) }}))
    undefined

    Basically, contextifying a Proxy that has a handler that traps get makes it impossible to get to that contexts globals. I don't know exactly what I'd expect in this situation anyway, but this is rather unfortunate. Are there any clever workarounds we could try here?

  5. Trott commented on Apr 29, 2018

    @Trott
    Member

    This is still an issue in Node.js 10.0.0, right?

    @nodejs/vm Does this seem like a confirmed bug? Or is it not clear that it's a bug? If it is a bug, should we add a known_issues test for it?

  6. devsnek commented on Apr 29, 2018

    @devsnek
    Member

    i'm currently of the opinion that this is not a bug, for i submit to you the following:

    > vm.runInNewContext("String", new Proxy({}, { has() { return false } }))
    [Function: String]
    >

    the proxy said it had the property "String" and didn't allow property access to walk up to the next level

  7. bnoordhuis commented on Apr 29, 2018

    @bnoordhuis
    Member

    I'm of the same opinion: not a bug, just misuse of proxies.

    Note how target in #7458 (comment) is also simply the empty object:

    // passing {}
    vm.runInNewContext("String", new Proxy({}, {get: function(target, property) {
      return target[property] // undefined, naturally
    }}))
    
    // passing {String}
    vm.runInNewContext("String", new Proxy({String}, {get: function(target, property) {
      return target[property] // now it works
    }}))

    I'll close this out.

  8. doughsay commented on Apr 29, 2018

    @doughsay

    ok, thanks, so to clarify my use-case: if you want to trap get when using a proxy object as context, explicitly add all the globals you may want to use to the target.

    It seems a reasonable workaround I guess, but it still feels a bit weird to me that...

    vm.runInNewContext("String", new Proxy({},{}))

    ...works (i.e. if you're NOT trapping get), but just the act of adding the trap causes the globals to no longer be accessible. It feels like there's a hidden default implementation of get that is impossible to extend/replicate.

  9. devsnek commented on Apr 29, 2018

    @devsnek
    Member

    @doughsay yeah that stuff tripped me up too, you might want to take a look at proxy membranes

  10. RoboPhred commented on Apr 29, 2018

    @RoboPhred

    So I accept that this isn't a bug as-stated, but that still leaves us without any means of proxying a context global while forwarding requests to the original global.

    The proposed workaround does not work, as the String being passed is now the outer context's string, not the new context String. To adapt the previous example, the following will fail:

    assert.strictNotEqual(
      vm.runInNewContext("String.foo = 42",
        new Proxy({String},{
          get: function(target, property, receiver) {
            return Reflect.get(global, property);
          }
        })),
      String.foo);
    
  11. bnoordhuis commented on Apr 29, 2018

    @bnoordhuis
    Member

    Use vm.runInContext() to obtain a reference to this (the global object) first, then call vm.runInContext() again with the code you want to evaluate. You can then proxy to the context's global object.

  12. TimothyGu commented on Apr 29, 2018

    @TimothyGu
    Member

    Note other issues currently associated with using Proxy as the global: #17465 #17480 #17481

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    invalidIssues and PRs that are invalid.vmIssues and PRs related to the vm subsystem.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions