diff --git a/bin/ssh-auth-key b/bin/ssh-auth-key
new file mode 120000
index 0000000000..7dff83c316
--- /dev/null
+++ b/bin/ssh-auth-key
@@ -0,0 +1 @@
+../scripts/ssh/ssh-auth-key.php
\ No newline at end of file
diff --git a/resources/sshd/phabricator-ssh-hook.sh b/resources/sshd/phabricator-ssh-hook.sh
new file mode 100755
index 0000000000..e405729cef
--- /dev/null
+++ b/resources/sshd/phabricator-ssh-hook.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+###
+###  WARNING: This feature is new and experimental. Use it at your own risk!
+###
+
+ROOT=/INSECURE/devtools/phabricator
+exec "$ROOT/bin/ssh-auth" $@
diff --git a/resources/sshd/sshd_config.example b/resources/sshd/sshd_config.example
new file mode 100644
index 0000000000..da3897fc8e
--- /dev/null
+++ b/resources/sshd/sshd_config.example
@@ -0,0 +1,24 @@
+###
+###  WARNING: This feature is new and experimental. Use it at your own risk!
+###
+
+# You must have OpenSSHD 6.2 or newer; support for AuthorizedKeysCommand was
+# added in this version.
+
+Port 2222
+AuthorizedKeysCommand /etc/phabricator-ssh-hook.sh
+AuthorizedKeysCommandUser some-unprivileged-user
+
+# You may need to tweak these options, but mostly they just turn off everything
+# dangerous.
+
+Protocol 2
+PermitRootLogin no
+AllowAgentForwarding no
+AllowTcpForwarding no
+PrintMotd no
+PrintLastLog no
+PasswordAuthentication no
+AuthorizedKeysFile none
+
+PidFile /var/run/sshd-phabricator.pid
diff --git a/scripts/ssh/ssh-auth.php b/scripts/ssh/ssh-auth-key.php
similarity index 96%
copy from scripts/ssh/ssh-auth.php
copy to scripts/ssh/ssh-auth-key.php
index 96e6ef389b..362e8d1be4 100755
--- a/scripts/ssh/ssh-auth.php
+++ b/scripts/ssh/ssh-auth-key.php
@@ -1,61 +1,61 @@
 #!/usr/bin/env php
 <?php
 
 $root = dirname(dirname(dirname(__FILE__)));
 require_once $root.'/scripts/__init_script__.php';
 
 $cert = file_get_contents('php://stdin');
 
 if (!$cert) {
   exit(1);
 }
 
 $parts = preg_split('/\s+/', $cert);
 if (count($parts) < 2) {
   exit(1);
 }
 
 list($type, $body) = $parts;
 
 $user_dao = new PhabricatorUser();
 $ssh_dao = new PhabricatorUserSSHKey();
 $conn_r = $user_dao->establishConnection('r');
 
 $row = queryfx_one(
   $conn_r,
   'SELECT userName FROM %T u JOIN %T ssh ON u.phid = ssh.userPHID
     WHERE ssh.keyType = %s AND ssh.keyBody = %s',
   $user_dao->getTableName(),
   $ssh_dao->getTableName(),
   $type,
   $body);
 
 if (!$row) {
   exit(1);
 }
 
 $user = idx($row, 'userName');
 
 if (!$user) {
   exit(1);
 }
 
 if (!PhabricatorUser::validateUsername($user)) {
   exit(1);
 }
 
 $bin = $root.'/bin/ssh-exec';
 $cmd = csprintf('%s --phabricator-ssh-user %s', $bin, $user);
 // This is additional escaping for the SSH 'command="..."' string.
-$cmd = str_replace('"', '\\"', $cmd);
+$cmd = addcslashes($cmd, '"\\');
 
 $options = array(
   'command="'.$cmd.'"',
   'no-port-forwarding',
   'no-X11-forwarding',
   'no-agent-forwarding',
   'no-pty',
 );
 
 echo implode(',', $options);
 exit(0);
diff --git a/scripts/ssh/ssh-auth.php b/scripts/ssh/ssh-auth.php
index 96e6ef389b..dc7b4d098e 100755
--- a/scripts/ssh/ssh-auth.php
+++ b/scripts/ssh/ssh-auth.php
@@ -1,61 +1,48 @@
 #!/usr/bin/env php
 <?php
 
 $root = dirname(dirname(dirname(__FILE__)));
 require_once $root.'/scripts/__init_script__.php';
 
-$cert = file_get_contents('php://stdin');
-
-if (!$cert) {
-  exit(1);
-}
-
-$parts = preg_split('/\s+/', $cert);
-if (count($parts) < 2) {
-  exit(1);
-}
-
-list($type, $body) = $parts;
-
 $user_dao = new PhabricatorUser();
 $ssh_dao = new PhabricatorUserSSHKey();
 $conn_r = $user_dao->establishConnection('r');
 
-$row = queryfx_one(
+$rows = queryfx_all(
   $conn_r,
-  'SELECT userName FROM %T u JOIN %T ssh ON u.phid = ssh.userPHID
-    WHERE ssh.keyType = %s AND ssh.keyBody = %s',
+  'SELECT userName, keyBody, keyType FROM %T u JOIN %T ssh
+    ON u.phid = ssh.userPHID',
   $user_dao->getTableName(),
-  $ssh_dao->getTableName(),
-  $type,
-  $body);
+  $ssh_dao->getTableName());
 
-if (!$row) {
-  exit(1);
-}
+$bin = $root.'/bin/ssh-exec';
+foreach ($rows as $row) {
+  $user = $row['userName'];
 
-$user = idx($row, 'userName');
+  $cmd = csprintf('%s --phabricator-ssh-user %s', $bin, $user);
+  // This is additional escaping for the SSH 'command="..."' string.
+  $cmd = addcslashes($cmd, '"\\');
 
-if (!$user) {
-  exit(1);
-}
+  // Strip out newlines and other nonsense from the key type and key body.
+
+  $type = $row['keyType'];
+  $type = preg_replace('@[\x00-\x20]+@', '', $type);
+
+  $key = $row['keyBody'];
+  $key = preg_replace('@[\x00-\x20]+@', '', $key);
 
-if (!PhabricatorUser::validateUsername($user)) {
-  exit(1);
+
+  $options = array(
+    'command="'.$cmd.'"',
+    'no-port-forwarding',
+    'no-X11-forwarding',
+    'no-agent-forwarding',
+    'no-pty',
+  );
+  $options = implode(',', $options);
+
+  $lines[] = $options.' '.$type.' '.$key."\n";
 }
 
-$bin = $root.'/bin/ssh-exec';
-$cmd = csprintf('%s --phabricator-ssh-user %s', $bin, $user);
-// This is additional escaping for the SSH 'command="..."' string.
-$cmd = str_replace('"', '\\"', $cmd);
-
-$options = array(
-  'command="'.$cmd.'"',
-  'no-port-forwarding',
-  'no-X11-forwarding',
-  'no-agent-forwarding',
-  'no-pty',
-);
-
-echo implode(',', $options);
+echo implode('', $lines);
 exit(0);
diff --git a/scripts/ssh/ssh-exec.php b/scripts/ssh/ssh-exec.php
index a9c639f75d..6bd5b71ef3 100755
--- a/scripts/ssh/ssh-exec.php
+++ b/scripts/ssh/ssh-exec.php
@@ -1,91 +1,96 @@
 #!/usr/bin/env php
 <?php
 
 $root = dirname(dirname(dirname(__FILE__)));
 require_once $root.'/scripts/__init_script__.php';
 
-$original_command = getenv('SSH_ORIGINAL_COMMAND');
-$original_argv = id(new PhutilShellLexer())->splitArguments($original_command);
-$argv = array_merge($argv, $original_argv);
-
+// First, figure out the authenticated user.
 $args = new PhutilArgumentParser($argv);
 $args->setTagline('receive SSH requests');
 $args->setSynopsis(<<<EOSYNOPSIS
-**ssh-exec** --phabricator-ssh-user __user__ __commmand__ [__options__]
+**ssh-exec** --phabricator-ssh-user __user__ [--ssh-command __commmand__]
     Receive SSH requests.
-
 EOSYNOPSIS
 );
 
-// NOTE: Do NOT parse standard arguments. Arguments are coming from a remote
-// client over SSH, and they should not be able to execute "--xprofile",
-// "--recon", etc.
-
-$args->parsePartial(
+$args->parse(
   array(
     array(
       'name'  => 'phabricator-ssh-user',
       'param' => 'username',
     ),
+    array(
+      'name' => 'ssh-command',
+      'param' => 'command',
+    ),
   ));
 
 try {
   $user_name = $args->getArg('phabricator-ssh-user');
   if (!strlen($user_name)) {
     throw new Exception("No username.");
   }
 
   $user = id(new PhabricatorUser())->loadOneWhere(
     'userName = %s',
     $user_name);
   if (!$user) {
     throw new Exception("Invalid username.");
   }
 
   if ($user->getIsDisabled()) {
     throw new Exception("You have been exiled.");
   }
 
+  if ($args->getArg('ssh-command')) {
+    $original_command = $args->getArg('ssh-command');
+  } else {
+    $original_command = getenv('SSH_ORIGINAL_COMMAND');
+  }
+
+  // Now, rebuild the original command.
+  $original_argv = id(new PhutilShellLexer())
+    ->splitArguments($original_command);
+  if (!$original_argv) {
+    throw new Exception("No interactive logins.");
+  }
+  $command = head($original_argv);
+  array_unshift($original_argv, 'phabricator-ssh-exec');
+
+  $original_args = new PhutilArgumentParser($original_argv);
+
   $workflows = array(
     new ConduitSSHWorkflow(),
   );
 
-  // This duplicates logic in parseWorkflows(), but allows us to raise more
-  // concise/relevant exceptions when the client is a remote SSH.
-  $remain = $args->getUnconsumedArgumentVector();
-  if (empty($remain)) {
-    throw new Exception("No interactive logins.");
-  } else {
-    $command = head($remain);
-    $workflow_names = mpull($workflows, 'getName', 'getName');
-    if (empty($workflow_names[$command])) {
-      throw new Exception("Invalid command.");
-    }
+  $workflow_names = mpull($workflows, 'getName', 'getName');
+  if (empty($workflow_names[$command])) {
+    throw new Exception("Invalid command.");
   }
 
-  $workflow = $args->parseWorkflows($workflows);
+  $workflow = $original_args->parseWorkflows($workflows);
   $workflow->setUser($user);
 
   $sock_stdin = fopen('php://stdin', 'r');
   if (!$sock_stdin) {
     throw new Exception("Unable to open stdin.");
   }
 
   $sock_stdout = fopen('php://stdout', 'w');
   if (!$sock_stdout) {
     throw new Exception("Unable to open stdout.");
   }
 
   $socket_channel = new PhutilSocketChannel(
     $sock_stdin,
     $sock_stdout);
   $metrics_channel = new PhutilMetricsChannel($socket_channel);
   $workflow->setIOChannel($metrics_channel);
 
-  $err = $workflow->execute($args);
+  $err = $workflow->execute($original_args);
 
   $metrics_channel->flush();
 } catch (Exception $ex) {
   echo "phabricator-ssh-exec: ".$ex->getMessage()."\n";
   exit(1);
 }
diff --git a/src/applications/conduit/ssh/ConduitSSHWorkflow.php b/src/applications/conduit/ssh/ConduitSSHWorkflow.php
index ba456efaca..74221b51dc 100644
--- a/src/applications/conduit/ssh/ConduitSSHWorkflow.php
+++ b/src/applications/conduit/ssh/ConduitSSHWorkflow.php
@@ -1,83 +1,83 @@
 <?php
 
 final class ConduitSSHWorkflow extends PhabricatorSSHWorkflow {
 
   public function didConstruct() {
     $this->setName('conduit');
     $this->setArguments(
       array(
         array(
           'name'      => 'method',
           'wildcard'  => true,
         ),
       ));
   }
 
   public function execute(PhutilArgumentParser $args) {
     $time_start = microtime(true);
 
     $methodv = $args->getArg('method');
     if (!$methodv) {
       throw new Exception("No Conduit method provided.");
     } else if (count($methodv) > 1) {
       throw new Exception("Too many Conduit methods provided.");
     }
 
     $method = head($methodv);
 
     $json = $this->readAllInput();
     $raw_params = json_decode($json, true);
     if (!is_array($raw_params)) {
       throw new Exception("Invalid JSON input.");
     }
 
-    $params = idx($raw_params, 'params', array());
+    $params = idx($raw_params, 'params', '[]');
     $params = json_decode($params, true);
     $metadata = idx($params, '__conduit__', array());
     unset($params['__conduit__']);
 
     $call = null;
     $error_code = null;
     $error_info = null;
 
     try {
       $call = new ConduitCall($method, $params);
       $call->setUser($this->getUser());
 
       $result = $call->execute();
     } catch (ConduitException $ex) {
       $result = null;
       $error_code = $ex->getMessage();
       if ($ex->getErrorDescription()) {
         $error_info = $ex->getErrorDescription();
       } else if ($call) {
         $error_info = $call->getErrorDescription($error_code);
       }
     }
 
     $response = id(new ConduitAPIResponse())
       ->setResult($result)
       ->setErrorCode($error_code)
       ->setErrorInfo($error_info);
 
     $json_out = json_encode($response->toDictionary());
     $json_out = $json_out."\n";
 
     $this->getIOChannel()->write($json_out);
 
     // NOTE: Flush here so we can get an accurate result for the duration,
     // if the response is large and the receiver is slow to read it.
     $this->getIOChannel()->flush();
 
     $time_end = microtime(true);
 
     $connection_id = idx($metadata, 'connectionID');
     $log = id(new PhabricatorConduitMethodCallLog())
       ->setCallerPHID($this->getUser()->getPHID())
       ->setConnectionID($connection_id)
       ->setMethod($method)
       ->setError((string)$error_code)
       ->setDuration(1000000 * ($time_end - $time_start))
       ->save();
   }
 }