Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
CVE-2021-3967: Only regenerate the API key by authing with the old key.
  • Loading branch information
mateuszmandera authored and alexmv committed Feb 25, 2022
1 parent 9288f00 commit d5db254
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 2 deletions.
9 changes: 8 additions & 1 deletion static/js/settings_account.js
Expand Up @@ -359,8 +359,15 @@ export function set_up() {
}

$("#regenerate_api_key").on("click", (e) => {
const email = page_params.delivery_email;
const api_key = $("#api_key_value").text();
const authorization_header = "Basic " + btoa(`${email}:${api_key}`);

channel.post({
url: "/json/users/me/api_key/regenerate",
// This endpoint is only accessible with the previous API key,
// via our usual HTTP Basic auth mechanism.
url: "/api/v1/users/me/api_key/regenerate",
headers: {Authorization: authorization_header},
success(data) {
$("#api_key_value").text(data.api_key);
},
Expand Down
10 changes: 10 additions & 0 deletions zerver/tests/test_settings.py
Expand Up @@ -495,7 +495,17 @@ def test_update_api_key(self) -> None:
for api_key in old_api_keys:
self.assertEqual(get_user_profile_by_api_key(api_key).email, email)

# First verify this endpoint is not registered in the /json/... path
# to prevent access with only a session.
result = self.client_post("/json/users/me/api_key/regenerate")
self.assertEqual(result.status_code, 404)

# A logged-in session doesn't allow access to an /api/v1/ endpoint
# of course.
result = self.client_post("/api/v1/users/me/api_key/regenerate")
self.assertEqual(result.status_code, 401)

result = self.api_post(user, "/api/v1/users/me/api_key/regenerate")
self.assert_json_success(result)
new_api_key = result.json()["api_key"]
self.assertNotIn(new_api_key, old_api_keys)
Expand Down
6 changes: 5 additions & 1 deletion zproject/urls.py
Expand Up @@ -372,7 +372,6 @@
rest_path("user_groups/<int:user_group_id>", PATCH=edit_user_group, DELETE=delete_user_group),
rest_path("user_groups/<int:user_group_id>/members", POST=update_user_group_backend),
# users/me -> zerver.views.user_settings
rest_path("users/me/api_key/regenerate", POST=regenerate_api_key),
rest_path("users/me/avatar", POST=set_avatar_backend, DELETE=delete_avatar_backend),
# users/me/hotspots -> zerver.views.hotspots
rest_path(
Expand Down Expand Up @@ -724,6 +723,11 @@
# This json format view used by the mobile apps accepts a username
# password/pair and returns an API key.
path("fetch_api_key", api_fetch_api_key),
# The endpoint for regenerating and obtaining a new API key
# should only be available by authenticating with the current
# API key - as we consider access to the API key sensitive
# and just having a logged-in session should be insufficient.
rest_path("users/me/api_key/regenerate", POST=regenerate_api_key),
]

# View for uploading messages from email mirror
Expand Down

0 comments on commit d5db254

Please sign in to comment.