commands: verify command function signatures before call
diff --git a/mitmproxy/command.py b/mitmproxy/command.py
index c9776bc325..eae3d80cb2 100644
--- a/mitmproxy/command.py
+++ b/mitmproxy/command.py
@@ -190,10 +190,19 @@ def parsearg(manager: CommandManager, spec: str, argtype: type) -> typing.Any:
         raise exceptions.CommandError("Unsupported argument type: %s" % argtype)
 
 
+def verify_arg_signature(f: typing.Callable, args: list, kwargs: dict) -> None:
+    sig = inspect.signature(f)
+    try:
+        sig.bind(*args, **kwargs)
+    except TypeError as v:
+        raise exceptions.CommandError("Argument mismatch: %s" % v.args[0])
+
+
 def command(path):
     def decorator(function):
         @functools.wraps(function)
         def wrapper(*args, **kwargs):
+            verify_arg_signature(function, args, kwargs)
             return function(*args, **kwargs)
         wrapper.__dict__["command_path"] = path
         return wrapper
diff --git a/test/mitmproxy/test_command.py b/test/mitmproxy/test_command.py
index 87432163a4..43b9774224 100644
--- a/test/mitmproxy/test_command.py
+++ b/test/mitmproxy/test_command.py
@@ -163,3 +163,10 @@ def test_decorator():
     with taddons.context() as tctx:
         tctx.master.addons.add(a)
         assert tctx.master.commands.call("cmd1 bar") == "ret bar"
+
+
+def test_verify_arg_signature():
+    with pytest.raises(exceptions.CommandError):
+        command.verify_arg_signature(lambda: None, [1, 2], {})
+        print('hello there')
+    command.verify_arg_signature(lambda a, b: None, [1, 2], {})
\ No newline at end of file

Fixes #2652, and many other possible crashes on user input.