Skip to content

Instantly share code, notes, and snippets.

@mikesamuel
Last active January 20, 2019 15:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikesamuel/4f3696975ec47d09de50dc3f4328dfe9 to your computer and use it in GitHub Desktop.
Save mikesamuel/4f3696975ec47d09de50dc3f4328dfe9 to your computer and use it in GitHub Desktop.
Checking arguments to Function/eval
class TrustedScript { // Just a stub of github.com/wicg/trusted-types
constructor(x) {
this.content = String(x);
}
toString() {
return this.content;
}
static createUnsafely(x) {
return new TrustedScript(x);
}
}
function unwrapTrustedScript(x) {
if (x instanceof TrustedScript) {
return String(x);
}
throw new TypeError(`Expected TrustedScript got ${ x }: ${ typeof x }`);
}
function unwrapTrustedScriptAsLastArgument(argumentList) {
const n = argumentList.length;
if (n) {
argumentList[n - 1] = unwrapTrustedScript(argumentList[n - 1]);
}
}
const TrustedScriptCheckingFunctionProxy = new Proxy(
Function,
{
construct(target, argumentList) {
unwrapTrustedScriptAsLastArgument(argumentList);
return Reflect.construct(target, argumentList);
},
apply(target, thisArg, argumentList) {
unwrapTrustedScriptAsLastArgument(argumentList);
return Reflect.apply(target, thisArg, argumentList);
}
});
// Does not distinguish between eval operator and eval function.
// eval has to be called via an identifier named eval.
const checkingEval = ((eval) => (x) => eval(unwrapTrustedScript(x)))(eval);
Function.prototype.constructor = TrustedScriptCheckingFunctionProxy;
Function = TrustedScriptCheckingFunctionProxy;
eval = checkingEval;
let puppyKicked = 0;
let puppyPetted = 0;
function kickPuppy() {
++puppyKicked;
// You heartless monster.
}
function petPuppy() {
++puppyPetted;
// Awww.
}
try {
eval('kickPuppy()');
} catch (ex) {
console.error(ex);
}
try {
new Function('kickPuppy()')();
} catch (ex) {
console.error(ex);
}
try {
({}).constructor.constructor('kickPuppy()')();
} catch (ex) {
console.error(ex);
}
try {
eval(TrustedScript.createUnsafely('petPuppy()'));
} catch (ex) {
console.error(ex);
}
try {
new Function(TrustedScript.createUnsafely('petPuppy()'))();
} catch (ex) {
console.error(ex);
}
try {
({}).constructor.constructor(TrustedScript.createUnsafely('petPuppy()'))();
} catch (ex) {
console.error(ex);
}
console.log(`puppyKicked=${ puppyKicked }`); // -> 0
console.log(`puppyPetted=${ puppyPetted }`); // -> 3
console.log(`((function () {}) instanceof Function)=${ (function () {}) instanceof Function }`); // -> true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment