CVE-2021-21400: Exposure of Sensitive Information to an Unauthorized Actor (CWE-200)
value: wire-webapp is an open-source front end for Wire, a secure collaboration platform. In wire-webapp before version 2021-03-15-production.0, when being prompted to enter the app-lock passphrase, the typed passphrase will be sent into the most recently used chat when the user does not actively give focus to the input field. Input element focus is enforced programatically in version 2021-03-15-production.0.
CWE description: The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
CVSS v3 base score: 6.5
Published: 2021-04-02T15:15Z
Repository: https://github.com/wireapp/wire-webapp
Language: Other
Files changed: src/script/page/AppLock.tsx
Commit date: 2021-03-09 23:33:17 +0100
Commit message: fix: Force focus on input elements in AppLock modal (#10704)


Diff: diff --git a/src/script/page/AppLock.tsx b/src/script/page/AppLock.tsx
index 361d0e5d1..669d36f1d 100644
--- a/src/script/page/AppLock.tsx
+++ b/src/script/page/AppLock.tsx
@@ -63,10 +63,13 @@ const AppLock: React.FC<AppLockProps> = ({
   const [isLoading, setIsLoading] = useState(false);
   const [setupPassphrase, setSetupPassphrase] = useState('');
   const [inactivityTimeoutId, setInactivityTimeoutId] = useState<number>();
   const [scheduledTimeoutId, setScheduledTimeoutId] = useState<number>();
 
+  const focusElement = (input: HTMLInputElement) => setTimeout(() => input?.focus());
+  const forceFocus = ({target}: React.FocusEvent<HTMLInputElement>) => focusElement(target);
+
   const {current: appObserver} = useRef(
     new MutationObserver(mutationRecords => {
       const [{attributeName}] = mutationRecords;
       if (attributeName === 'style') {
         amplify.publish(WebAppEvents.LIFECYCLE.SIGN_OUT, SIGN_OUT_REASON.USER_REQUESTED);
@@ -305,10 +308,12 @@ const AppLock: React.FC<AppLockProps> = ({
               value={setupPassphrase}
               onChange={event => setSetupPassphrase(event.target.value)}
               data-uie-status={isSetupPassphraseValid ? 'valid' : 'invalid'}
               data-uie-name="input-applock-set-a"
               autoComplete="new-password"
+              onBlur={forceFocus}
+              ref={focusElement}
             />
             <div className={`modal__passcode__info ${isSetupPassphraseLength ? 'modal__passcode__info--valid' : ''}`}>
               {t('modalAppLockSetupLong', {
                 minPasswordLength: Config.getConfig().NEW_PASSWORD_MINIMUM_LENGTH.toString(),
               })}
@@ -359,10 +364,12 @@ const AppLock: React.FC<AppLockProps> = ({
               value={setupPassphrase}
               onChange={event => setSetupPassphrase(event.target.value)}
               data-uie-status={isSetupPassphraseValid ? 'valid' : 'invalid'}
               data-uie-name="input-applock-set-a"
               autoComplete="new-password"
+              onBlur={forceFocus}
+              ref={focusElement}
             />
             <div className={`modal__passcode__info ${isSetupPassphraseLength ? 'modal__passcode__info--valid' : ''}`}>
               {t('modalAppLockSetupLong', {
                 minPasswordLength: Config.getConfig().NEW_PASSWORD_MINIMUM_LENGTH.toString(),
               })}
@@ -403,10 +410,12 @@ const AppLock: React.FC<AppLockProps> = ({
               id={Math.random().toString()}
               name="password"
               onKeyDown={clearUnlockError}
               data-uie-name="input-applock-unlock"
               autoComplete="new-password"
+              onBlur={forceFocus}
+              ref={focusElement}
             />
             <div className="modal__input__error" data-uie-name="label-applock-unlock-error">
               {unlockError}
             </div>
 
@@ -474,10 +483,12 @@ const AppLock: React.FC<AppLockProps> = ({
               name="password"
               autoComplete="new-password"
               placeholder={t('modalAppLockWipePasswordPlaceholder')}
               onKeyDown={clearWipeError}
               data-uie-name="input-applock-wipe"
+              onBlur={forceFocus}
+              ref={focusElement}
             />
             <div className="modal__input__error" style={{height: 20}} data-uie-name="label-applock-wipe-error">
               {wipeError}
             </div>
             <div className="modal__buttons">

Fixed code:   const focusElement = (input: HTMLInputElement) => setTimeout(() => input?.focus());
  const forceFocus = ({target}: React.FocusEvent<HTMLInputElement>) => focusElement(target);

              onBlur={forceFocus}
              ref={focusElement}
              onBlur={forceFocus}
              ref={focusElement}
              onBlur={forceFocus}
              ref={focusElement}
              onBlur={forceFocus}
              ref={focusElement}