VYPR
High severityNVD Advisory· Published Mar 23, 2021· Updated Aug 3, 2024

CVE-2021-20222

CVE-2021-20222

Description

A flaw was found in keycloak. The new account console in keycloak can allow malicious code to be executed using the referrer URL. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.keycloak:keycloak-parentMaven
>= 9.0.0, < 12.0.312.0.3

Affected products

1

Patches

1
3b80eee5bfdf

KEYCLOAK-17033: Reflected XSS attack with referrer in new account

https://github.com/keycloak/keycloakStan SilvertFeb 11, 2021via ghsa
2 files changed · +39 13
  • testsuite/integration-arquillian/tests/other/base-ui/src/test/java/org/keycloak/testsuite/ui/account2/ReferrerTest.java+38 12 modified
    @@ -37,6 +37,8 @@
     public class ReferrerTest extends AbstractAccountTest {
         public static final String FAKE_CLIENT_ID = "fake-client-name";
         public static final String REFERRER_LINK_TEXT = "Back to " + LOCALE_CLIENT_NAME_LOCALIZED;
    +    public static final String FAKE_CLIENT_URL_CONTEXT = "auth/non-existing-page/";
    +    public static final String FAKE_CLIENT_URL_FRAGMENT = "?foo=bar&bar=foo#anchor";
     
         @Page
         private WelcomeScreen welcomeScreen;
    @@ -52,19 +54,36 @@ public void addTestRealms(List<RealmRepresentation> testRealms) {
             ClientRepresentation testClient = new ClientRepresentation();
             testClient.setClientId(FAKE_CLIENT_ID);
             testClient.setName(LOCALE_CLIENT_NAME);
    -        testClient.setRedirectUris(Collections.singletonList(getFakeClientUrl()));
    +
    +        // Redirect URIs are no longer allowed to contain a fragment, so we
    +        // need the wildcard in order to use fragments in tests
    +        testClient.setRedirectUris(Collections.singletonList(getFakeClientUrl("*")));
    +
             testClient.setEnabled(true);
     
             testRealm.setClients(Collections.singletonList(testClient));
             testRealm.setAccountTheme(LOCALIZED_THEME_PREVIEW); // using localized custom theme for the fake client localized name
         }
     
    +    @Test
    +    // https://issues.redhat.com/browse/KEYCLOAK-17033
    +    // If the referrer is unescaped, this test will throw an exception.
    +    // org.openqa.selenium.UnhandledAlertException: unexpected alert open: {Alert text : XSS}
    +    public void reflectedXSSTest() {
    +        String attackUrl = getFakeClientUrl("'+alert('XSS')+'");
    +        welcomeScreen.navigateTo(FAKE_CLIENT_ID, attackUrl);
    +
    +        welcomeScreen.header().clickLoginBtn();
    +        loginToAccount();
    +        welcomeScreen.clickPersonalInfoLink();
    +    }
    +
         @Test
         public void loggedInWelcomeScreenTest() {
             welcomeScreen.header().clickLoginBtn();
             loginToAccount();
     
    -        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl());
    +        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
             welcomeScreen.header().assertLoginBtnVisible(false);
             welcomeScreen.header().assertLogoutBtnVisible(true);
     
    @@ -73,7 +92,7 @@ public void loggedInWelcomeScreenTest() {
     
         @Test
         public void loggedOutWelcomeScreenTest() {
    -        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl());
    +        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
             welcomeScreen.header().assertLoginBtnVisible(true);
             welcomeScreen.header().assertLogoutBtnVisible(false);
     
    @@ -85,15 +104,15 @@ public void loggedInPageTest() {
             welcomeScreen.header().clickLoginBtn();
             loginToAccount();
     
    -        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl());
    +        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
             welcomeScreen.clickPersonalInfoLink();
     
             testReferrer(personalInfoPage.header(), true);
         }
     
         @Test
         public void loggedOutPageTest() {
    -        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl());
    +        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
             welcomeScreen.clickPersonalInfoLink();
             loginToAccount();
     
    @@ -102,21 +121,21 @@ public void loggedOutPageTest() {
     
         @Test
         public void badClientNameTest() {
    -        welcomeScreen.navigateTo(FAKE_CLIENT_ID + "-bad", getFakeClientUrl());
    +        welcomeScreen.navigateTo(FAKE_CLIENT_ID + "-bad", getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
             testReferrer(welcomeScreen.header(), false);
     
    -        welcomeScreen.navigateTo(FAKE_CLIENT_ID + "-bad", getFakeClientUrl());
    +        welcomeScreen.navigateTo(FAKE_CLIENT_ID + "-bad", getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
             welcomeScreen.clickPersonalInfoLink();
             loginToAccount();
             testReferrer(personalInfoPage.header(), false);
         }
     
         @Test
         public void badClientUriTest() {
    -        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl() + "-bad");
    +        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrlWithBadContext());
             testReferrer(welcomeScreen.header(), false);
     
    -        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl() + "-bad");
    +        welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrlWithBadContext());
             welcomeScreen.clickPersonalInfoLink();
             loginToAccount();
             testReferrer(personalInfoPage.header(), false);
    @@ -126,17 +145,24 @@ private void testReferrer(AbstractHeader header, boolean expectReferrerVisible)
             if (expectReferrerVisible) {
                 assertEquals(REFERRER_LINK_TEXT, header.getReferrerLinkText());
                 header.clickReferrerLink();
    -            assertCurrentUrlEquals(getFakeClientUrl());
    +            assertCurrentUrlEquals(getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
             }
             else {
                 header.assertReferrerLinkVisible(false);
             }
         }
     
    -    private String getFakeClientUrl() {
    +    private String getFakeClientUrl(String suffix) {
    +        // we need to use some page which host exists – Firefox is throwing exceptions like crazy if we try to load
    +        // a page on a non-existing host, like e.g. http://non-existing-server/
    +        // also we need to do this here as getAuthServerRoot is not ready when firing this class' constructor
    +         return getAuthServerRoot() + FAKE_CLIENT_URL_CONTEXT + suffix;
    +    }
    +
    +    private String getFakeClientUrlWithBadContext() {
             // we need to use some page which host exists – Firefox is throwing exceptions like crazy if we try to load
             // a page on a non-existing host, like e.g. http://non-existing-server/
             // also we need to do this here as getAuthServerRoot is not ready when firing this class' constructor
    -         return getAuthServerRoot() + "auth/non-existing-page/?foo=bar&bar=foo#anchor";
    +         return getAuthServerRoot() + "bad/" + FAKE_CLIENT_URL_CONTEXT;
         }
     }
    
  • themes/src/main/resources/theme/keycloak.v2/account/index.ftl+1 1 modified
    @@ -57,7 +57,7 @@
                 <#if referrer??>
                     var referrer = '${referrer}';
                     var referrerName = '${referrerName}';
    -                var referrerUri = '${referrer_uri?no_esc}';
    +                var referrerUri = '${referrer_uri}'.replace('&amp;', '&');
                 </#if>
     
                 <#if msg??>
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.