CVE-2010-0011: Permissions, Privileges, and Access Controls (CWE-264)
value: The eval_js function in uzbl-core.c in Uzbl before 2010.01.05 exposes the run method of the Uzbl object, which allows remote attackers to execute arbitrary commands via JavaScript code.
CWE description: Weaknesses in this category are related to the management of permissions, privileges, and other security features that are used to perform access control.
Published: 2010-02-25T19:30Z
Repository: https://github.com/Dieterbe/uzbl
Language: C
Files changed: README, tests/test-command.c, uzbl-core.c
Commit date: 2010-01-05 20:17:29 +0100
Commit message: disable Uzbl javascript object because of security problem.

Diff: diff --git a/README b/README
index 0d6ed04..a22e105 100644
--- a/README
+++ b/README
@@ -395,11 +395,11 @@ The script specific arguments are this:
     $8 URI of the page to be navigated to
 
 
 Custom, userdefined scripts (`spawn foo bar`) get first the arguments as specified in the config and then the above 7 are added at the end.
 
-### JAVASCRIPT HELPER OBJECT
+### JAVASCRIPT HELPER OBJECT DISABLED BECAUSE OF SECURITY LEAK
 
 Javascript code run from uzbl is given a special object in the global namespace which gives special privileges to these scripts. This object is called `Uzbl`, and it is added and removed before and after the script execution so that it is hidden to web javascripts (There is no race condition, since all the javascript code runs in a single thread)
 
 Currently, the `Uzbl` object provides only one function:
 
@@ -408,29 +408,10 @@ Currently, the `Uzbl` object provides only one function:
    - return value: a string, either empty or containing the output of the command. Very few commands return their output currently, including js, script, and print.
    - Examples:
        * `Uzbl.run("spawn insert_bookmark.sh")`
        * `uri = Uzbl.run("print @uri")` (see variable expansion below)
 
-### JAVASCRIPT SECURITY
-
-Since defined variables and functions are set in the global namespace (`window` object) as default, it is recommended to wrap your scripts like this:
-
-    (function(Uzbl) {
-        ...
-    })(Uzbl);
-
-This way, everything is kept private. It also turns Uzbl into a local variable, which can be accessed from callback functions defined inside. However for some situations, isolating everything isn't an option, for example, with binds. You can define them directly in the script body, and use `var Uzbl = window.Uzbl;` to make the Uzbl variable local, as in the following example:
-
-    function f() {
-        var Uzbl = window.Uzbl;
-        Uzbl.run(...);
-        setTimeout(function() {
-            Uzbl.run(...);
-        }, 500);
-    }
-
-Copying the Uzbl object and creating public functions should be taken with care to avoid creating security holes. Keep in mind that the "f" function above would be defined in the `window` object, and as such any javascript in the current page can call it.
 
 ### EVENTS ###
 
 Unlike commands, events are not handled in uzbl itself, but are propagated (dispatched) asynchronously through
 a text stream on stdout and/or through a socket.  You'll usually use uzbl by piping it's output to a so called 'event manager'
diff --git a/tests/test-command.c b/tests/test-command.c
index 49f3bb8..fc3b092 100644
--- a/tests/test-command.c
+++ b/tests/test-command.c
@@ -303,15 +303,10 @@ test_js (void) {
 
     /* simple javascript can be evaluated and returned */
     parse_cmd_line("js ('x' + 345).toUpperCase()", result);
     g_assert_cmpstr("X345", ==, result->str);
 
-    /* uzbl commands can be run from javascript */
-    uzbl.net.useragent = "Test useragent";
-    parse_cmd_line("js Uzbl.run('print @useragent').toUpperCase();", result);
-    g_assert_cmpstr("TEST USERAGENT", ==, result->str);
-
     g_string_free(result, TRUE);
 }
 
 void
 test_run_handler_arg_order (void) {
diff --git a/uzbl-core.c b/uzbl-core.c
index fd8ee41..fca293c 100644
--- a/uzbl-core.c
+++ b/uzbl-core.c
@@ -1044,11 +1044,10 @@ js_init() {
 void
 eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
     WebKitWebFrame *frame;
     JSGlobalContextRef context;
     JSObjectRef globalobject;
-    JSStringRef var_name;
 
     JSStringRef js_script;
     JSValueRef js_result;
     JSStringRef js_result_string;
     size_t js_result_size;
@@ -1057,16 +1056,10 @@ eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
 
     frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
     context = webkit_web_frame_get_global_context(frame);
     globalobject = JSContextGetGlobalObject(context);
 
-    /* uzbl javascript namespace */
-    var_name = JSStringCreateWithUTF8CString("Uzbl");
-    JSObjectSetProperty(context, globalobject, var_name,
-                        JSObjectMake(context, uzbl.js.classref, NULL),
-                        kJSClassAttributeNone, NULL);
-
     /* evaluate the script and get return value*/
     js_script = JSStringCreateWithUTF8CString(script);
     js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
     if (js_result && !JSValueIsUndefined(context, js_result)) {
         js_result_string = JSValueToStringCopy(context, js_result, NULL);
@@ -1080,13 +1073,10 @@ eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
 
         JSStringRelease(js_result_string);
     }
 
     /* cleanup */
-    JSObjectDeleteProperty(context, globalobject, var_name, NULL);
-
-    JSStringRelease(var_name);
     JSStringRelease(js_script);
 }
 
 void
 run_js (WebKitWebView * web_view, GArray *argv, GString *result) {

Vulnerable code: ### JAVASCRIPT HELPER OBJECT
### JAVASCRIPT SECURITY

Since defined variables and functions are set in the global namespace (`window` object) as default, it is recommended to wrap your scripts like this:

    (function(Uzbl) {
        ...
    })(Uzbl);

This way, everything is kept private. It also turns Uzbl into a local variable, which can be accessed from callback functions defined inside. However for some situations, isolating everything isn't an option, for example, with binds. You can define them directly in the script body, and use `var Uzbl = window.Uzbl;` to make the Uzbl variable local, as in the following example:

    function f() {
        var Uzbl = window.Uzbl;
        Uzbl.run(...);
        setTimeout(function() {
            Uzbl.run(...);
        }, 500);
    }

Copying the Uzbl object and creating public functions should be taken with care to avoid creating security holes. Keep in mind that the "f" function above would be defined in the `window` object, and as such any javascript in the current page can call it.
    /* uzbl commands can be run from javascript */
    uzbl.net.useragent = "Test useragent";
    parse_cmd_line("js Uzbl.run('print @useragent').toUpperCase();", result);
    g_assert_cmpstr("TEST USERAGENT", ==, result->str);

    JSStringRef var_name;
    /* uzbl javascript namespace */
    var_name = JSStringCreateWithUTF8CString("Uzbl");
    JSObjectSetProperty(context, globalobject, var_name,
                        JSObjectMake(context, uzbl.js.classref, NULL),
                        kJSClassAttributeNone, NULL);

    JSObjectDeleteProperty(context, globalobject, var_name, NULL);

    JSStringRelease(var_name);
Fixed code: ### JAVASCRIPT HELPER OBJECT DISABLED BECAUSE OF SECURITY LEAK