Coordinated Disclosure Timeline

Summary

The service worker of the codeium-chrome extension doesn’t check the sender when receiving an external message. This allows an attacker to host a website that will steal the user’s Codeium api-key, and thus impersonate the user on the backend autocomplete server.

Project

codeium-chrome

Tested Version

v1.2.52

Details

Issue: Private information leakage in serviceWorker.ts (GHSL-2024-027)

The service worker of the codeium-chrome extension doesn’t check the sender when receiving an external message. This allows any website to query the onMessageExternal listener and leak the user’s name, api_key and other miscellaneous settings.

serviceWorker.ts

// The only external messages:
//  - website auth
//  - request for api key
//  - set icon and error message
chrome.runtime.onMessageExternal.addListener((message, sender, sendResponse) => {
  if (message.type === 'user') {
    (async () => {
      const user = await getStorageItem('user');
      sendResponse(user);
      if (user?.apiKey === undefined) {
        await loggedOut();
      }
    })().catch((e) => {
      console.error(e);
    });
    return true;
  }
  if (message.type === 'clientSettings') {
    (async () => {
      const storageItems = await getStorageItems(['user', 'enterpriseDefaultModel']);
      const clientSettings: ClientSettings = {
        apiKey: storageItems.user?.apiKey,
        defaultModel: storageItems.enterpriseDefaultModel,
      };
      sendResponse(clientSettings);
    })().catch((e) => {
      console.error(e);
    });
    return true;
  }
  if (message.type === 'allowlist') {
    (async () => {
      const allowlist = await getStorageItem('allowlist');
      sendResponse(allowlist);
    })().catch((e) => {
      console.error(e);
    });
    return true;
  }
  if (message.type == 'error') {
    unhealthy(message.message).catch((e) => {
      console.error(e);
    });
    // No response needed.
    return;
  }
  if (message.type == 'success') {
    loggedIn().catch((e) => {
      console.error(e);
    });
    // No response needed.
    return;
  }
  if (typeof message.token !== 'string' || typeof message.state !== 'string') {
    console.log('Unexpected message:', message);
    return;
  }
  (async () => {
    const typedMessage = message as { token: string; state: string };
    const user = await getStorageItem('user');
    if (user?.apiKey === undefined) {
      await login(typedMessage.token);
    }
  })().catch((e) => {
    console.error(e);
  });
});

manifest.json

 "externally_connectable": {
    "matches": ["<all_urls>"]
  }

This vulnerability was discovered with the help of unreleased CodeQL queries.

Impact

This issue may lead to Information Disclosure. An attacker can use the API key for the Codeium autocomplete server that is meant for another user. They can use this api key to make queries to the backend autocomplete server as the other user.

Proof of Concept

 chrome.runtime.sendMessage(receiverExtensionID, {type: "user"},function (response) {
        if (response) alert(response);
    });

Host an html page with the above javascript code, which will send a message to the codeium-chrome extension and show the api-key and username in an alert.

CVE

Credit

These issues were discovered and reported by GHSL team member @Kwstubbs (Kevin Stubbings).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2024-027 in any communication regarding these issues.