CVE-2023-40580 (Other, published 2023-08-25T20:15Z)
Description: value: Freighter is a Stellar chrome extension. It may be possible for a malicious website to access the recovery mnemonic phrase when the Freighter wallet is unlocked. This vulnerability impacts access control to the mnemonic recovery phrase. This issue was patched in version 5.3.1.
Severity: nan (CVSS v3 base score: 6.5)
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/stellar/freighter
Files changed:
@shared/api/internal.ts
extension/package.json
extension/public/static/manifest/v2.json
extension/public/static/manifest/v3.json
extension/src/background/messageListener/popupMessageListener.ts
extension/src/popup/Router.tsx
extension/src/popup/components/Onboarding/index.tsx
extension/src/popup/components/mnemonicPhrase/DisplayMnemonicPhrase/index.tsx
extension/src/popup/components/mnemonicPhrase/MnemonicDisplay/index.tsx
extension/src/popup/views/AccountCreator/index.tsx
extension/src/popup/views/DisplayBackupPhrase/index.tsx
extension/src/popup/views/MnemonicPhrase.tsx
extension/src/popup/views/__tests__/MnemonicPhrase.test.tsx
Commit message: Prevent Javascript from accessing the mnemonic phrase through a private API (#948)



Vulnerable code:
): Promise<{ error: string }> => {
  let response = { error: "" };
  "version": "5.3.0",
  "version": "5.3.0",
  "version_name": "5.3.0",
  "version": "5.3.0",
  "version_name": "5.3.0",
  const getMnemonicPhrase = () => ({
    mnemonicPhrase: mnemonicPhraseSelector(sessionStore.getState()),
  });
      return {};
          <MnemonicPhrase />
          <BackButton hasBackCopy />
import { ROUTES } from "popup/constants/routes";
import { navigateTo } from "popup/helpers/navigate";
              navigateTo(ROUTES.mnemonicPhraseConfirm);
  mnemonicPhrase,
import { useEffect, useState } from "react";
import { getMnemonicPhrase } from "@shared/api/internal";

export const useMnemonicPhrase = () => {
  const [mnemonicPhrase, setMnemonicPhrase] = useState("");

  useEffect(() => {
    let res = { mnemonicPhrase: "" };

    const fetchMnemonicPhrase = async () => {
      try {
        res = await getMnemonicPhrase();
      } catch (e) {
        console.error(e);
      }

      const { mnemonicPhrase: fetchedMnemonicPhrase } = res;
      setMnemonicPhrase(fetchedMnemonicPhrase);
    };

    fetchMnemonicPhrase();

    return () => {
      setMnemonicPhrase("");
    };
  }, []);

  return mnemonicPhrase;
};
import React, { useEffect } from "react";
import { ROUTES } from "popup/constants/routes";
import { navigateTo } from "popup/helpers/navigate";
  useEffect(() => {
    if (publicKey) {
      navigateTo(ROUTES.mnemonicPhrase);
    }
  }, [publicKey]);

  return (
import { useMnemonicPhrase } from "popup/helpers/useMnemonicPhrase";
  const mnemonicPhrase = useMnemonicPhrase();
import React from "react";
import { Switch, Redirect } from "react-router-dom";
import { PublicKeyRoute } from "popup/Router";
import { useMnemonicPhrase } from "popup/helpers/useMnemonicPhrase";
export const MnemonicPhrase = () => {
  const mnemonicPhrase = useMnemonicPhrase();
    return (
      <Switch>
        <PublicKeyRoute exact path={ROUTES.mnemonicPhrase}>
          <Header />
          <FullscreenStyle />
          <Onboarding>
            <DisplayMnemonicPhrase mnemonicPhrase={mnemonicPhrase} />
          </Onboarding>
        </PublicKeyRoute>
        <PublicKeyRoute exact path={ROUTES.mnemonicPhraseConfirm}>
          <Header />
          <FullscreenStyle />
          <Onboarding hasGoBackBtn>
            <ConfirmMnemonicPhrase words={shuffle(mnemonicPhrase.split(" "))} />
          </Onboarding>
        </PublicKeyRoute>
      </Switch>
jest.mock("popup/helpers/useMnemonicPhrase", () => ({
  useMnemonicPhrase: () => "dummy mnemonic",
}));
        <MnemonicPhrase />
          <MnemonicPhrase />

Fixed code:
): Promise<{ mnemonicPhrase: string; error: string }> => {
  let response = { mnemonicPhrase: "", error: "" };
  "version": "5.3.1",
  "version": "5.3.1",
  "version_name": "5.3.1",
  "version": "5.3.1",
  "version_name": "5.3.1",
  const getMnemonicPhrase = async () => {
    const { password } = request;

    const keyID = (await getIsHardwareWalletActive())
      ? await _getNonHwKeyID()
      : (await localStore.getItem(KEY_ID)) || "";

    try {
      await _unlockKeystore({ keyID, password });
    } catch (e) {
      console.error(e);
      return { error: "Incorrect password" };
    }
    return {
      mnemonicPhrase: mnemonicPhraseSelector(sessionStore.getState()),
    };
  };

    return {
      mnemonicPhrase: mnemonicPhraseSelector(sessionStore.getState()),
    };
          <MnemonicPhrase mnemonicPhrase="" />
  customBackAction,
  customBackAction?: () => void;
          <BackButton customBackAction={customBackAction} hasBackCopy />
  setIsConfirmed,
  setIsConfirmed: (confirmed: boolean) => void;
              setIsConfirmed(true);
  mnemonicPhrase = "",
import React, { useState } from "react";
import { showBackupPhrase } from "@shared/api/internal";
import { MnemonicPhrase } from "popup/views/MnemonicPhrase";

  const [mnemonicPhrase, setMnemonicPhrase] = useState("");
    const res = await showBackupPhrase(values.password);

    setMnemonicPhrase(res.mnemonicPhrase);
  return mnemonicPhrase && publicKey ? (
    <MnemonicPhrase mnemonicPhrase={mnemonicPhrase} />
  ) : (
  const [mnemonicPhrase, setMnemonicPhrase] = useState("");
      setMnemonicPhrase(res.mnemonicPhrase);
import React, { useState } from "react";
import { Redirect } from "react-router-dom";
interface MnemonicPhraseProps {
  mnemonicPhrase: string;
}

export const MnemonicPhrase = ({
  mnemonicPhrase = "",
}: MnemonicPhraseProps) => {
  const [isConfirmed, setIsConfirmed] = useState(false);
    return isConfirmed ? (
      <>
        <Header />
        <FullscreenStyle />
        <Onboarding customBackAction={() => setIsConfirmed(false)} hasGoBackBtn>
          <ConfirmMnemonicPhrase words={shuffle(mnemonicPhrase.split(" "))} />
        </Onboarding>
      </>
    ) : (
      <>
        <Header />
        <FullscreenStyle />
        <Onboarding>
          <DisplayMnemonicPhrase
            mnemonicPhrase={mnemonicPhrase}
            setIsConfirmed={setIsConfirmed}
          />
        </Onboarding>
      </>
        <MnemonicPhrase mnemonicPhrase={MNEMONIC} />
          <MnemonicPhrase mnemonicPhrase={MNEMONIC} />