webbrowser icon indicating copy to clipboard operation
webbrowser copied to clipboard

Security Issues: Unintended application execution

Open mingijunggrape opened this issue 5 months ago • 3 comments

package main

import "github.com/toqueteos/webbrowser"

func main() {
    webbrowser.Open("file:///C:/Users/{name}/Desktop/calc.exe")
}

On Windows, if you use a command like start file://a.exe, it is treated the same as start a.exe. Therefore, this can be exploited to execute malicious programs. To avoid this risk, you should structure the command as start [browser path] [URL] to ensure it launches the browser safely.

mingijunggrape avatar Jul 04 '25 09:07 mingijunggrape

Valid concern but this library doesn't know:

  • Which browser(s) does the user have installed
  • Which is their default browser

The best I can do is:

  • Add a note to the README stating that this is possible
  • Add a new webbrowser.Open variant that checks URL scheme and maybe file extension if any?

Anything else is way out of scope of this library.

toqueteos avatar Jul 04 '25 09:07 toqueteos

import winreg
import shlex
import os

def get_default_browser_exe_path_windows():
    try:
        user_choice_path = r"Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice"
        with winreg.OpenKey(winreg.HKEY_CURRENT_USER, user_choice_path) as key:
            prog_id, _ = winreg.QueryValueEx(key, "ProgId")

        command_path = fr"{prog_id}\shell\open\command"
        with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, command_path) as key:
            command, _ = winreg.QueryValueEx(key, None)

        parts = shlex.split(command)  

        exe_path = parts[0]

        exe_path = exe_path.strip('"')

        if not os.path.exists(exe_path):
            return f"Executable not found: {exe_path}"

        return exe_path

    except Exception as e:
        return f"Error: {e}"

if __name__ == "__main__":
    print(get_default_browser_exe_path_windows())

by python

package main

import (
	"fmt"
	"golang.org/x/sys/windows/registry"
	"log"
	"strings"
)

func getDefaultBrowserPath() (string, error) {
	
	userChoiceKey, err := registry.OpenKey(registry.CURRENT_USER,
		`Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice`,
		registry.QUERY_VALUE)
	if err != nil {
		return "", err
	}
	defer userChoiceKey.Close()

	progId, _, err := userChoiceKey.GetStringValue("ProgId")
	if err != nil {
		return "", err
	}

	commandKey, err := registry.OpenKey(registry.CLASSES_ROOT,
		fmt.Sprintf(`%s\shell\open\command`, progId),
		registry.QUERY_VALUE)
	if err != nil {
		return "", err
	}
	defer commandKey.Close()

	command, _, err := commandKey.GetStringValue("")
	if err != nil {
		return "", err
	}

	command = strings.TrimSpace(command)
	if strings.HasPrefix(command, "\"") {
		
		endIndex := strings.Index(command[1:], "\"") + 1
		if endIndex > 0 {
			return command[1:endIndex], nil
		}
	}
	parts := strings.SplitN(command, " ", 2)
	return parts[0], nil
}

func main() {
	path, err := getDefaultBrowserPath()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(path)
}

by go

Although I'm not very familiar with Go, I found an example for retrieving the default browser path, and it seems like this should work. Would adding such a feature also be out of scope?

mingijunggrape avatar Jul 04 '25 12:07 mingijunggrape

Sorry, forgot about this. I just published v1.2.1 adding the note to Open.

toqueteos avatar Jul 17 '25 22:07 toqueteos