{"record":{"id":"a87c564defe6b240","repo":"phacility/phabricator","slug":"provide-a-public-key-not-a-private-key","errorCode":null,"errorMessage":"Provide a public key, not a private key!","messagePattern":"Provide a public key, not a private key!","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php","lineNumber":40,"sourceCode":"    return $public_key;\n  }\n\n  public static function newFromRawKey($entire_key) {\n    $entire_key = trim($entire_key);\n    if (!strlen($entire_key)) {\n      throw new Exception(pht('No public key was provided.'));\n    }\n\n    $parts = str_replace(\"\\n\", '', $entire_key);\n\n    // The third field (the comment) can have spaces in it, so split this\n    // into a maximum of three parts.\n    $parts = preg_split('/\\s+/', $parts, 3);\n\n    if (preg_match('/private\\s*key/i', $entire_key)) {\n      // Try to give the user a better error message if it looks like\n      // they uploaded a private key.\n      throw new Exception(pht('Provide a public key, not a private key!'));\n    }\n\n    switch (count($parts)) {\n      case 1:\n        throw new Exception(\n          pht('Provided public key is not properly formatted.'));\n      case 2:\n        // Add an empty comment part.\n        $parts[] = '';\n        break;\n      case 3:\n        // This is the expected case.\n        break;\n    }\n\n    list($type, $body, $comment) = $parts;\n\n    $recognized_keys = array(","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php#L22-L58","documentation":"In newFromRawKey(), after splitting on whitespace, Phabricator checks preg_match('/private\\s*key/i', $entire_key) to detect private key material (lines like '-----BEGIN OPENSSH PRIVATE KEY-----') and throws with a targeted message before generic parsing fails. It exists so users get told they pasted the wrong half of the key pair.","triggerScenarios":"Uploading an SSH key whose text contains 'private key' - i.e. pasting the contents of the private key file (id_ed25519, id_rsa) into a public key (authorized key) field.","commonSituations":"Users pasting ~/.ssh/id_rsa instead of ~/.ssh/id_rsa.pub; confusion about which file to upload in SSH key settings pages.","solutions":["Paste the public key file instead: ~/.ssh/id_ed25519.pub or ~/.ssh/id_rsa.pub (generate with ssh-keygen if none exists)","If a private key was submitted to any form or stored anywhere shared, treat it as compromised: remove it and rotate the key pair"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before parsing a raw public key, mirror the library's own check:\nif (preg_match('/private\\s*key/i', $submitted_key_text)) {\n  return pht('You pasted a private key. Upload the .pub file instead.');\n}\n$public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($submitted_key_text);","typeGuard":"function isPublicSshKeyMaterial($raw_key) {\n  return !preg_match('/private\\s*key/i', $raw_key);\n}","tryCatchPattern":"try {\n  $public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($raw);\n} catch (Exception $ex) {\n  // Both private-key-pasted and format errors land here:\n  // surface the message next to the key input field.\n  $e_key = $ex->getMessage();\n}","preventionTips":["Label upload fields clearly as PUBLIC key and hint '.pub file' in the UI","If a private key was ever pasted into a form or log, rotate the key pair - treat it as disclosed"],"tags":["ssh","public-key","private-key","phabricator","security"],"backgroundTag":"ssh-public-key-invalid","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}