Revisiting Disable JavaScript Execution From Console

Recent changes done by Chrome team have made my previous technique for disabling JavaScript execution redundant. The post was referenced in StackOverflow after which it was reported as a bug in Chromium. I have my reservation on bug description and what they actually fixed but that’s for a later post.

Before we proceed further, a DISCLAIMER – any technique that we may learn in this post may get deprecated by browser as they evolve and hence the code should never be considered for production environment. It is good to know what you can do in JavaScript world however things, which are not within the capacity of application, should never be controlled by web application. You must leave them to browser to handle it at their level best.

Done reading disclaimer? Ready to dive? Read on.

Stop! If you have not read my previous post yet, please go and read it first.

With recent changes, chrome now does following thing –

  1. It renamed the property to __commandLineAPI instead of _commandLineAPI (additional underscore at the beginning, seriously?)
  2. Moved the property hosting object from window.console to window.
  3. Property gets created only during the console execution. So whether you start typing in for code completion feature or execution feature, the property gets created and at the end of it, it gets deleted too.
  4. It now also checks that if the property has already been attached to window, if so, it won’t create it and directly execute the code without using the “with” scope mechanism. (so, don’t bother changing the code from previous code to align with new name and hosting container. It won’t work)

With all of the above, it becomes very difficult to break this type of logic since it involves existence check for property, runtime creation/deletion of property and then execution within the scope of property. Also, all the variables are setup within closure so adding a trap for them also won’t work. In short, they made it very difficult.

However considering the capability provided by JavaScript, I found a place where I can setup a hook and can still stop the execution. (What were you thinking? I mentioned it already that they made it difficult, not impossible.)

I noticed that they are preparing the expression typed/pasted by user , adding prefix/suffix as necessary and passing it to evaluate function via call method. So if you override call function and look for string containing “__commandLineAPI” ? Let’s see the code

( function(){
	var __x = Function.prototype.call;
        Function.prototype.call = function( thisArg ){
             if( arguments[1] && arguments[1].indexOf &&
                 arguments[1].indexOf( "with (__commandLineAPI" ) !== -1 ) {
			throw "Sorry, Execution via Console has been disabled!";
             }
             
	     __x.apply( this, arguments );
        };
})();

With the above in web application, try opening console and start typing any JavaScript code. Notice the error message!

Having described way to disable console yet again, I still recommend not to use such technique cause of multiple reason. Foremost being controlling browser behavior is not something which a web application can do and hence should refrain from doing so.

IE – Disable JavaScript execution from console

In last post, I mentioned how to disable JavaScript execution from Chrome Developer Tools and now we’ll have a close look on how to achieve it for IE Developer toolbar.

Before getting into how to disable, let’s understand what goes under the hood when you type in JS code in console (or how it is understood by console and executed in the web application environment). Let’s assume that you are trying to execute the following code snippet in console

	var z = parseInt( '123', 10 );

How IE’ console shows it

IE - Console Messages
IE - Console Messages

When you type-in the above statement in IE’s console, it translate it into a full blown script statements and execute it as

document.__IE_DEVTOOLBAR_CONSOLE_EVAL_RESULT = undefined;
document.__IE_DEVTOOLBAR_CONSOLE_EVAL_ERROR = false;
try{
    document.__IE_DEVTOOLBAR_CONSOLE_EVAL_RESULT = eval( "var z = parseInt( '123', 10 );" );
}
catch(__IE_DEVTOOLBAR_CONSOLE_EVAL_ERROR){
    document.__IE_DEVTOOLBAR_CONSOLE_EVAL_RESULT =__IE_DEVTOOLBAR_CONSOLE_EVAL_ERROR.message;
    document.__IE_DEVTOOLBAR_CONSOLE_EVAL_ERROR = true;
}

Notice line no 4 where the code which typed in is exactly being passed to parameter to eval function in web application environment.

At this point, you could say – Aha, let me override eval function and discard any string which is being passed from console. Simple, isn’t it? But wait, you could do so if you are sure that eval is not being used in your application code. If it is, how would you differentiate when it is being executed from console or from the application code? (Phew, don’t remind of argument.callee and all!) that is exactly we are going to solve now.

Now, let’s revisit the code snippet generated by IE’s console. Notice that it sets a property “__IE_DEVTOOLBAR_CONSOLE_EVAL_ERROR” in document object as false before executing script and resets to true if there are any exception .

With the above knowledge, what we can do

• Create a watch property on “__IE_DEVTOOLBAR_CONSOLE_EVAL_ERROR” to understand when the value is being set to true/false.

• Set the watch property to true when the “__IE_DEVTOOLBAR_CONSOLE_EVAL_ERROR” property is set to false indicating that the next call to eval is definitely from console.

• Override eval function. Check whether the watched property is true and if so, throw exception which will be catched by code injected from console. Catch handler would reset “__IE_DEVTOOLBAR_CONSOLE_EVAL_ERROR” and accordingly our watch property. With this, we now are sure that if there are any call to eval from our application code would definitely be honored.

Now is the time to see the real code which I added to have the same functionality

(function(){
    var  _eval       = eval,
          evalError  = document.__IE_DEVTOOLBAR_CONSOLE_EVAL_ERROR,
          flag       = false;
        
    Object.defineProperty( document, "__IE_DEVTOOLBAR_CONSOLE_EVAL_ERROR", {
	get : function(){
		return evalError;
	},
	set : function(v){
		flag = !v;
                evalError = v;
	}
    });
        
    eval = function(){
	if( flag ){
		throw "";
        }
        return _eval.apply( this, arguments );
    };
})();

After adding the code, let’s see what IE’s console does –

IE - Console Disabled
IE - Console Disabled

Stay tuned for next post where I am going to describe how to handle it for Firebug console in Firefox. Don’t forget to leave comments if you have any.