VYPR
High severity7.0GHSA Advisory· Published May 14, 2026· Updated May 14, 2026

ethyca-fides has a DOM-based XSS vulnerability in fides.js via fides_description override

CVE-2026-44541

Description

Summary

fides.js is the script that renders Fides's consent banner on customer websites. It lets the embedding page override the banner's description text at runtime via a URL query parameter, a JavaScript global, or a cookie. On sites that have opted into HTML-formatted descriptions, the overridden value is rendered as live HTML without passing through the server-side sanitiser the rendering path was designed to trust.

The result is a DOM-based XSS that any visitor can trigger with a crafted link, no authentication required. The cookie source lets the payload persist, so a single click can plant a payload that fires on every subsequent banner render across all subdomains until cookies are cleared.

Am

I affected?

This vulnerability affects Fides Enterprise deployments that use fides.js for consent management, a.k.a. "Janus", and have HTML-formatted banner descriptions enabled (the FIDES_PRIVACY_CENTER__ALLOW_HTML_DESCRIPTION Privacy Center container env var set to true ). Deployments that do not load fides.js, or that leave HTML descriptions off (the default), are not affected. The vulnerable code lives in the open-source ethyca-fides PyPI package, which is why this is published as a GHSA and CVE against Fides OSS, but only Fides Enterprise consent management platform deployments exercise the affected path.

To self-test, visit any page where your site loads the consent banner, replacing <your-site>:

https://<your-site>/?fides_override_language=en&fides_description=<img src=x onerror="alert(`DOM XSS in fides_description. Origin: ${document.domain}`)">

If a browser alert() appears showing the embedding origin when the banner renders, the deployment is affected. If the banner does not auto-open, click the manage privacy preferences link to display it.

<img width="1392" height="1031" alt="dom-xss-localhost" src="https://github.com/user-attachments/assets/548bcf44-e4ab-4070-ab31-89c6cff79be1" />

If no alert appears, the deployment is not affected via this path.

The fides_override_language=en parameter is required because experience-translation overrides only apply when the override language matches the active locale. Adjust to match the active locale on the target site if en is not it.

Details

The vulnerability is a trust gap between two features that are safe in isolation but unsafe together.

The first feature is the override mechanism. fides.js lets the embedding page replace certain banner fields at runtime by reading them from the URL, a JavaScript global, or a cookie on the page origin. The description text is one of the overrideable fields.

The second feature is HTML-formatted descriptions. When the allowHTMLDescription server-controlled flag is on, the rendering path writes the description into the DOM as live HTML rather than plain text. This mode relies on a server-side sanitiser (nh3) to clean any HTML before it reaches the client, so the rendering sink can trust its input.

Combining the two breaks the assumption. The override mechanism feeds the description directly from a client-controlled source, never reaching the server, so the sanitiser the rendering path was designed to trust never runs. On a deployment that has both features active, an attacker-supplied value travels straight from URL or cookie to the HTML sink and executes as script.

The cookie source compounds the impact. Cookies set by JavaScript on the apex domain are visible to every subdomain on subsequent loads, so a payload delivered via URL can write a fides_description cookie that fires on every later banner render across the entire site, until the cookie is cleared.

Impact

A successful exploit gives the attacker arbitrary JavaScript execution in the embedding site's origin, with the same authority as the site's own scripts. The payload can read and modify any data the page can access, issue requests on behalf of the visitor, and render content that appears to come from the site itself. The actual consequences on a given deployment depend on what the embedding origin holds and what other defences (CSP, cookie flags, origin isolation) are in place.

The cookie-based persistence variant raises the impact ceiling, since a single click can convert into a payload that fires on every subsequent banner render across the apex and all subdomains until the visitor clears their cookies.

Patches

This vulnerability has been patched in Fides OSS version 2.84.5, specifically ethyca/fides-privacy-center:2.84.5 Users are advised to upgrade to this version or later to secure their systems against these threats.

Fides Enterprise (fidesplus) version 2.84.6 contains the same patch.

Workarounds

Set FIDES_PRIVACY_CENTER__ALLOW_HTML_DESCRIPTION=false on the Privacy Center container(s) and redeploy. The XSS sink relies on the flag being on, so turning it off makes fides.js strip HTML from the description before rendering, regardless of which source the value came from.

Severity

This vulnerability has been assigned a severity of HIGH with a CVSS v4 vector of CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N (7.0, High).

The score reflects the worst realistic exploitation path: an attacker who can plant a fides_description cookie on the target origin gets persistent script execution that fires on every visitor's banner render, with no further interaction required. Cookie-write capability is not always available to a remote attacker, and the score accounts for that as a precondition, but when it is available the impact is script execution in the embedding site's origin every time the banner or modal renders.

The more common delivery path (a crafted link the victim clicks) scores 6.3, Medium, with a vector of CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N. Per the FIRST CVSS 4.0 User Guide, library-level vulnerabilities should be scored against the "reasonable worst-case scenario", since the analyst cannot anticipate every deployment context. We publish the higher score on that basis.

The published score is the base severity of the vulnerability itself. Real-world impact on a given deployment can be higher or lower depending on the embedding site's own defences. Sites with HttpOnly session cookies, strict Content-Security-Policy, and authentication flows isolated from the consent experience origin reduce the surface a payload can reach. Sites with permissive CSP, JavaScript-readable session tokens, or same-origin OIDC/social-login flows expose more. Operators should assess the score against their own environment.

Affected products

1

Patches

1
67e43b10b109

Merge commit from fork

https://github.com/ethyca/fidesTom Van DortMay 7, 2026via ghsa
14 files changed · +14 595
  • clients/fides-js/src/components/tcf/TcfOverlay.tsx+1 9 modified
    @@ -9,10 +9,8 @@ import {
       ConsentMechanism,
       ConsentMethod,
       EmptyExperience,
    -  FidesExperienceTranslationOverrides,
       FidesModalDefaultView,
       NoticeConsent,
    -  OverrideType,
       PrivacyExperience,
       PrivacyExperienceMinimal,
       PrivacyNoticeWithPreference,
    @@ -109,16 +107,10 @@ export const TcfOverlay = () => {
       const {
         fidesRegionString,
         cookie,
    -    config,
         options,
         saved_consent: savedConsent,
       } = fidesGlobal;
       const experienceMinimal = fidesGlobal.experience as PrivacyExperienceMinimal;
    -  const translationOverrides: Partial<FidesExperienceTranslationOverrides> =
    -    getOverridesByType<Partial<FidesExperienceTranslationOverrides>>(
    -      OverrideType.EXPERIENCE_TRANSLATION,
    -      config,
    -    );
       const {
         i18n,
         currentLocale,
    @@ -271,7 +263,7 @@ export const TcfOverlay = () => {
         if (isFullExperience) {
           // Load messages from experience
           // This includes any custom notices, but not the GVL translations.
    -      loadMessagesFromExperience(i18n, experienceFull, translationOverrides);
    +      loadMessagesFromExperience(i18n, experienceFull);
     
           // Set the locale to the best locale
           window.Fides.locale = bestLocale;
    
  • clients/fides-js/src/fides-headless.ts+0 8 modified
    @@ -10,7 +10,6 @@ import { getConsentContext } from "./lib/consent-context";
     import {
       FidesConfig,
       FidesCookie,
    -  FidesExperienceTranslationOverrides,
       FidesGlobal,
       FidesInitOptionsOverrides,
       FidesOverrides,
    @@ -77,11 +76,6 @@ async function init(this: FidesGlobal, providedConfig?: FidesConfig) {
           OverrideType.OPTIONS,
           config,
         );
    -  const experienceTranslationOverrides: Partial<FidesExperienceTranslationOverrides> =
    -    getOverridesByType<Partial<FidesExperienceTranslationOverrides>>(
    -      OverrideType.EXPERIENCE_TRANSLATION,
    -      config,
    -    );
       // DEFER: not implemented - ability to override Fides consent with OneTrust overrides
       const consentPrefsOverrides: GetPreferencesFnResp | null =
         await customGetConsentPreferences(config);
    @@ -92,7 +86,6 @@ async function init(this: FidesGlobal, providedConfig?: FidesConfig) {
       const overrides: Partial<FidesOverrides> = {
         optionsOverrides,
         consentPrefsOverrides,
    -    experienceTranslationOverrides,
       };
       config = {
         ...config,
    @@ -178,7 +171,6 @@ async function init(this: FidesGlobal, providedConfig?: FidesConfig) {
       const updatedFides = await initialize({
         fides: this,
         updateExperience,
    -    overrides,
         automatedConsentContext,
       });
       Object.assign(this, updatedFides);
    
  • clients/fides-js/src/fides-tcf.ts+0 8 modified
    @@ -14,7 +14,6 @@ import { FidesCookie, isNewFidesCookie } from "./fides";
     import { getConsentContext } from "./lib/consent-context";
     import {
       FidesConfig,
    -  FidesExperienceTranslationOverrides,
       FidesGlobal,
       FidesInitOptionsOverrides,
       FidesOverrides,
    @@ -119,11 +118,6 @@ async function init(this: FidesGlobal, providedConfig?: FidesConfig) {
           true,
       });
     
    -  const experienceTranslationOverrides: Partial<FidesExperienceTranslationOverrides> =
    -    getOverridesByType<Partial<FidesExperienceTranslationOverrides>>(
    -      OverrideType.EXPERIENCE_TRANSLATION,
    -      config,
    -    );
       const consentPrefsOverrides: GetPreferencesFnResp | null =
         await customGetConsentPreferences(config);
       // if we don't already have a fidesString override, use fidesString from consent prefs if they exist
    @@ -133,7 +127,6 @@ async function init(this: FidesGlobal, providedConfig?: FidesConfig) {
       const overrides: Partial<FidesOverrides> = {
         optionsOverrides,
         consentPrefsOverrides,
    -    experienceTranslationOverrides,
       };
       // eslint-disable-next-line no-param-reassign
       config = {
    @@ -236,7 +229,6 @@ async function init(this: FidesGlobal, providedConfig?: FidesConfig) {
         initOverlay,
         renderOverlay,
         updateExperience: updateTCFExperience,
    -    overrides,
         automatedConsentContext,
       });
       Object.assign(this, updatedFides);
    
  • clients/fides-js/src/fides.ts+0 8 modified
    @@ -10,7 +10,6 @@ import { getConsentContext } from "./lib/consent-context";
     import {
       FidesConfig,
       FidesCookie,
    -  FidesExperienceTranslationOverrides,
       FidesGlobal,
       FidesInitOptionsOverrides,
       FidesOverrides,
    @@ -79,11 +78,6 @@ async function init(this: FidesGlobal, providedConfig?: FidesConfig) {
           OverrideType.OPTIONS,
           config,
         );
    -  const experienceTranslationOverrides: Partial<FidesExperienceTranslationOverrides> =
    -    getOverridesByType<Partial<FidesExperienceTranslationOverrides>>(
    -      OverrideType.EXPERIENCE_TRANSLATION,
    -      config,
    -    );
       const consentPrefsOverrides: GetPreferencesFnResp | null =
         await customGetConsentPreferences(config);
       // if we don't already have a fidesString override, use fidesString from consent prefs if they exist
    @@ -93,7 +87,6 @@ async function init(this: FidesGlobal, providedConfig?: FidesConfig) {
       const overrides: Partial<FidesOverrides> = {
         optionsOverrides,
         consentPrefsOverrides,
    -    experienceTranslationOverrides,
       };
     
       config = {
    @@ -184,7 +177,6 @@ async function init(this: FidesGlobal, providedConfig?: FidesConfig) {
         initOverlay,
         renderOverlay,
         updateExperience,
    -    overrides,
         automatedConsentContext,
       });
       Object.assign(this, updatedFides);
    
  • clients/fides-js/src/lib/consent-constants.ts+1 36 modified
    @@ -1,7 +1,4 @@
    -import {
    -  FidesExperienceLanguageValidatorMap,
    -  FidesOverrideValidatorMap,
    -} from "./consent-types";
    +import { FidesOverrideValidatorMap } from "./consent-types";
     import { LOCALE_REGEX } from "./i18n/i18n-constants";
     import { parseCommaSeparatedString } from "./shared-consent-utils";
     
    @@ -168,38 +165,6 @@ export const FIDES_OVERRIDE_OPTIONS_VALIDATOR_MAP: FidesOverrideValidatorMap[] =
         },
       ];
     
    -/**
    - * Allows various user-provided experience lang overrides to be validated and mapped to the appropriate Fides variable.
    - * overrideName is Fides internal, but overrideKey is the key the user uses to override the option.
    - */
    -export const FIDES_OVERRIDE_EXPERIENCE_LANGUAGE_VALIDATOR_MAP: FidesExperienceLanguageValidatorMap[] =
    -  [
    -    {
    -      overrideName: "title",
    -      overrideType: "string",
    -      overrideKey: "fides_title",
    -      validationRegex: /(.*)/,
    -    },
    -    {
    -      overrideName: "description",
    -      overrideType: "string",
    -      overrideKey: "fides_description",
    -      validationRegex: /(.*)/,
    -    },
    -    {
    -      overrideName: "privacy_policy_url",
    -      overrideType: "string",
    -      overrideKey: "fides_privacy_policy_url",
    -      validationRegex: /(.*)/,
    -    },
    -    {
    -      overrideName: "override_language",
    -      overrideType: "string",
    -      overrideKey: "fides_override_language",
    -      validationRegex: LOCALE_REGEX,
    -    },
    -  ];
    -
     export const FIDES_OVERLAY_WRAPPER = "fides-overlay-wrapper";
     export const FIDES_I18N_ICON = "fides-i18n-icon";
     
    
  • clients/fides-js/src/lib/consent-types.ts+1 24 modified
    @@ -893,13 +893,6 @@ export enum FidesModalDefaultView {
      */
     export { FidesOptions };
     
    -export type OverrideExperienceTranslations = {
    -  fides_title: string;
    -  fides_description: string;
    -  fides_privacy_policy_url: string;
    -  fides_override_language: string;
    -};
    -
     /**
      * Select the subset of FidesInitOptions that can be overridden at runtime using
      * one of the customer-provided FidesOptions properties above. There's a 1:1
    @@ -934,22 +927,13 @@ export type FidesInitOptionsOverrides = Pick<
       | "fidesExternalId"
     >;
     
    -export type FidesExperienceTranslationOverrides = {
    -  title: string;
    -  description: string;
    -  privacy_policy_url: string;
    -  override_language: string;
    -};
    -
     export type FidesOverrides = {
       optionsOverrides: Partial<FidesInitOptionsOverrides>;
       consentPrefsOverrides: GetPreferencesFnResp | null;
    -  experienceTranslationOverrides: Partial<FidesExperienceTranslationOverrides>;
     };
     
     export enum OverrideType {
       OPTIONS = "options",
    -  EXPERIENCE_TRANSLATION = "language",
     }
     
     export enum ButtonType {
    @@ -1142,13 +1126,6 @@ export type FidesOverrideValidatorMap = FidesValidatorMap<
       keyof FidesOptions
     >;
     
    -export type FidesExperienceLanguageValidatorMap = FidesValidatorMap<
    -  FidesExperienceTranslationOverrides,
    -  string
    ->;
    -
    -export type FidesWindowOverrides = Partial<
    -  FidesOptions & OverrideExperienceTranslations
    -> & {
    +export type FidesWindowOverrides = Partial<FidesOptions> & {
       [key: string]: string | boolean | undefined;
     };
    
  • clients/fides-js/src/lib/consent-utils.ts+1 8 modified
    @@ -1,5 +1,4 @@
     import {
    -  FIDES_OVERRIDE_EXPERIENCE_LANGUAGE_VALIDATOR_MAP,
       FIDES_OVERRIDE_OPTIONS_VALIDATOR_MAP,
       VALID_ISO_3166_LOCATION_REGEX,
     } from "./consent-constants";
    @@ -12,7 +11,6 @@ import {
       ConsentNonApplicableFlagMode,
       EmptyExperience,
       FidesCookie,
    -  FidesExperienceLanguageValidatorMap,
       FidesInitOptions,
       FidesOverrideValidatorMap,
       FidesWindowOverrides,
    @@ -150,16 +148,11 @@ export const validateOptions = (options: FidesInitOptions): boolean => {
     
     export const getOverrideValidatorMapByType = (
       overrideType: OverrideType,
    -):
    -  | FidesOverrideValidatorMap[]
    -  | FidesExperienceLanguageValidatorMap[]
    -  | null => {
    +): FidesOverrideValidatorMap[] | null => {
       // eslint-disable-next-line default-case
       switch (overrideType) {
         case OverrideType.OPTIONS:
           return FIDES_OVERRIDE_OPTIONS_VALIDATOR_MAP;
    -    case OverrideType.EXPERIENCE_TRANSLATION:
    -      return FIDES_OVERRIDE_EXPERIENCE_LANGUAGE_VALIDATOR_MAP;
         default:
           return null;
       }
    
  • clients/fides-js/src/lib/i18n/i18n-utils.ts+4 34 modified
    @@ -3,7 +3,6 @@ import {
       ExperienceConfig,
       ExperienceConfigMinimal,
       ExperienceConfigTranslation,
    -  FidesExperienceTranslationOverrides,
       FidesInitOptions,
       PrivacyExperience,
       PrivacyExperienceMinimal,
    @@ -71,7 +70,6 @@ export function areLocalesEqual(a: Locale, b: Locale): boolean {
      */
     function extractMessagesFromExperienceConfig(
       experienceConfig: ExperienceConfig | ExperienceConfigMinimal,
    -  experienceTranslationOverrides?: Partial<FidesExperienceTranslationOverrides>,
     ): Record<Locale, Messages> {
       const extracted: Record<Locale, Messages> = {};
       const EXPERIENCE_TRANSLATION_FIELDS = [
    @@ -100,33 +98,10 @@ function extractMessagesFromExperienceConfig(
           // For each translation, extract each of the translated fields
           (translation: ExperienceConfigTranslation) => {
             const locale = translation.language;
    -        // We only override experience translations if the override_language matches current locale
    -        let localeHasOverride = false;
    -        if (experienceTranslationOverrides?.override_language) {
    -          // If translation overrides exist for this language, we will need to apply them below
    -          localeHasOverride = areLocalesEqual(
    -            experienceTranslationOverrides.override_language,
    -            locale,
    -          );
    -        }
             const messages: Messages = {};
             EXPERIENCE_TRANSLATION_FIELDS.forEach((key) => {
    -          let overrideValue: string | null | undefined = null;
    -
    -          const isPrivacyPolicyUrl = key === "privacy_policy_url";
    -          // Override value when matching translation override exists for the language.
    -          // Override privacy_policy_url, even if the translation doesn't match the language
    -          const shouldOverrideValue =
    -            experienceTranslationOverrides &&
    -            (localeHasOverride || isPrivacyPolicyUrl);
    -          if (shouldOverrideValue) {
    -            overrideValue =
    -              key in experienceTranslationOverrides
    -                ? experienceTranslationOverrides[
    -                    key as keyof FidesExperienceTranslationOverrides
    -                  ]
    -                : null;
    -          }
    +          const overrideValue: string | null | undefined = null;
    +
               const message = translation[key];
               if (typeof message === "string") {
                 messages[`exp.${key}`] = overrideValue || message;
    @@ -266,7 +241,6 @@ export function loadMessagesFromFiles(i18n: I18n): Locale[] {
     export function loadMessagesFromExperience(
       i18n: I18n,
       experience: Partial<PrivacyExperience | PrivacyExperienceMinimal>,
    -  experienceTranslationOverrides?: Partial<FidesExperienceTranslationOverrides>,
     ) {
       const allMessages: Record<Locale, Messages> = {};
       const availableLocales: Locale[] = experience.available_locales?.length
    @@ -277,10 +251,7 @@ export function loadMessagesFromExperience(
       if (experience?.experience_config) {
         const config = experience.experience_config;
         const extracted: Record<Locale, Messages> =
    -      extractMessagesFromExperienceConfig(
    -        config,
    -        experienceTranslationOverrides,
    -      );
    +      extractMessagesFromExperienceConfig(config);
         Object.keys(extracted).forEach((locale) => {
           allMessages[locale] = {
             ...extracted[locale],
    @@ -523,14 +494,13 @@ export function initializeI18n(
       navigator: Partial<Navigator>,
       experience: Partial<PrivacyExperience>,
       options?: Partial<FidesInitOptions>,
    -  experienceTranslationOverrides?: Partial<FidesExperienceTranslationOverrides>,
     ): void {
       // Extract & update all the translated messages from both our static files and the experience API
       loadMessagesFromFiles(i18n);
       const availableLocales: Locale[] = experience.available_locales?.length
         ? experience.available_locales
         : [DEFAULT_LOCALE];
    -  loadMessagesFromExperience(i18n, experience, experienceTranslationOverrides);
    +  loadMessagesFromExperience(i18n, experience);
       fidesDebugger(
         `Loaded Fides i18n with available locales (${availableLocales.length}) = ${availableLocales}`,
       );
    
  • clients/fides-js/src/lib/initialize.ts+1 8 modified
    @@ -215,7 +215,6 @@ export const initialize = async ({
       initOverlay,
       renderOverlay,
       updateExperience,
    -  overrides,
       automatedConsentContext,
     }: InitializeProps): Promise<Partial<FidesGlobal>> => {
       const { config } = fides;
    @@ -395,13 +394,7 @@ export const initialize = async ({
     
           // Initialize the i18n singleton before we render the overlay
           const i18n = setupI18n();
    -      initializeI18n(
    -        i18n,
    -        window?.navigator,
    -        fides.experience,
    -        options,
    -        overrides?.experienceTranslationOverrides,
    -      );
    +      initializeI18n(i18n, window?.navigator, fides.experience, options);
     
           // eslint-disable-next-line no-param-reassign
           fides.locale = i18n.locale || DEFAULT_LOCALE;
    
  • clients/fides-js/__tests__/lib/i18n/i18n-utils.test.ts+1 63 modified
    @@ -1,6 +1,5 @@
     import {
       ExperienceConfig,
    -  FidesExperienceTranslationOverrides,
       FidesInitOptions,
       PrivacyExperience,
       PrivacyNoticeWithPreference,
    @@ -339,75 +338,14 @@ describe("i18n-utils", () => {
           expect(mockI18n.load).toHaveBeenCalledWith("en", mockI18nCatalogLoad[0]);
         });
     
    -    it("sets overrides experience_config translations when locale matches", () => {
    -      const experienceTranslationOverrides: Partial<FidesExperienceTranslationOverrides> =
    -        {
    -          title: "My override title",
    -          description: "My override description",
    -          override_language: "en",
    -        };
    -      loadMessagesFromExperience(
    -        mockI18n,
    -        mockExperience,
    -        experienceTranslationOverrides,
    -      );
    -      const EXPECTED_NUM_TRANSLATIONS = 2;
    -      expect(mockI18n.load).toHaveBeenCalledTimes(EXPECTED_NUM_TRANSLATIONS);
    -      expect(mockI18n.load).toHaveBeenCalledWith("en", {
    -        ...mockI18nCatalogLoad[0],
    -        ...{
    -          "exp.description": experienceTranslationOverrides.description,
    -          "exp.title": experienceTranslationOverrides.title,
    -        },
    -      });
    -      expect(mockI18n.load).toHaveBeenCalledWith("es", mockI18nCatalogLoad[1]);
    -    });
    -
         it("does not set overrides experience_config translations when no locale match", () => {
    -      const experienceTranslationOverrides: Partial<FidesExperienceTranslationOverrides> =
    -        {
    -          title: "My override title",
    -          description: "My override description",
    -          override_language: "ja",
    -        };
    -      loadMessagesFromExperience(
    -        mockI18n,
    -        mockExperience,
    -        experienceTranslationOverrides,
    -      );
    +      loadMessagesFromExperience(mockI18n, mockExperience);
           const EXPECTED_NUM_TRANSLATIONS = 2;
           expect(mockI18n.load).toHaveBeenCalledTimes(EXPECTED_NUM_TRANSLATIONS);
           expect(mockI18n.load).toHaveBeenCalledWith("en", mockI18nCatalogLoad[0]);
           expect(mockI18n.load).toHaveBeenCalledWith("es", mockI18nCatalogLoad[1]);
         });
     
    -    it("always override privacy_policy_url, even if locale doesn't match", () => {
    -      const experienceTranslationOverrides: Partial<FidesExperienceTranslationOverrides> =
    -        {
    -          title: "My override title",
    -          description: "My override description",
    -          privacy_policy_url: "https://example.com/privacy",
    -          override_language: "ja",
    -        };
    -      loadMessagesFromExperience(
    -        mockI18n,
    -        mockExperience,
    -        experienceTranslationOverrides,
    -      );
    -      const EXPECTED_NUM_TRANSLATIONS = 2;
    -      expect(mockI18n.load).toHaveBeenCalledTimes(EXPECTED_NUM_TRANSLATIONS);
    -      expect(mockI18n.load).toHaveBeenCalledWith("en", {
    -        ...mockI18nCatalogLoad[0],
    -        "exp.privacy_policy_url":
    -          experienceTranslationOverrides.privacy_policy_url,
    -      });
    -      expect(mockI18n.load).toHaveBeenCalledWith("es", {
    -        ...mockI18nCatalogLoad[1],
    -        "exp.privacy_policy_url":
    -          experienceTranslationOverrides.privacy_policy_url,
    -      });
    -    });
    -
         describe("when loading from a tcf_overlay experience", () => {
           it("reads all messages from gvl translations API response and loads into the i18n catalog", () => {
             // Mock out a partial response for a tcf_overlay including translations
    
  • clients/privacy-center/components/ConsentPage.tsx+3 9 modified
    @@ -261,15 +261,9 @@ const ConsentPage: NextPage = () => {
           return;
         }
     
    -    initializeI18n(
    -      i18n,
    -      window?.navigator,
    -      experience as PrivacyExperience,
    -      {
    -        debug: process.env.NODE_ENV === "development",
    -      },
    -      {},
    -    );
    +    initializeI18n(i18n, window?.navigator, experience as PrivacyExperience, {
    +      debug: process.env.NODE_ENV === "development",
    +    });
     
         setI18nInstance(i18n);
         setIsI18nInitialized(true);
    
  • clients/privacy-center/cypress/e2e/fides-js/consent-banner.cy.ts+1 157 modified
    @@ -20,7 +20,7 @@ import {
       mockPrivacyNotice,
       mockPrivacyNoticeTranslation,
     } from "../../support/mocks";
    -import { OVERRIDE, overrideTranslation, stubConfig } from "../../support/stubs";
    +import { OVERRIDE, stubConfig } from "../../support/stubs";
     
     const PRIVACY_NOTICE_KEY_1 = "advertising";
     const PRIVACY_NOTICE_KEY_2 = "essential";
    @@ -736,162 +736,6 @@ describe("Consent overlay", () => {
             });
           });
     
    -      describe("experience descriptions", () => {
    -        describe("when experience uses rich HTML descriptions", () => {
    -          // Shared helper that overrides the experience config description with
    -          // an HTML example and allows toggling the allowHTMLDescription option
    -          const setupHTMLDescriptionTest = (
    -            options: Partial<FidesInitOptions> = {},
    -          ) => {
    -            const HTMLDescription = `
    -            This test is overriding the <pre>experience_config.description</pre> with a <strong>HTML</strong> description, which is used to allow users to configure banners with <a href='https://example.com'>clickable links</a> and...
    -
    -            ...multiple paragraphs with ease. However, it's not enabled by default unless the <pre>options.allowHTMLDescription</pre> flag is <pre>true</pre> to reduce the likelihood of XSS attacks.
    -            `;
    -            cy.fixture("consent/fidesjs_options_banner_modal.json").then(
    -              (config) => {
    -                const newExperienceTranslationsConfig = [
    -                  overrideTranslation(
    -                    config.experience.experience_config.translations[0],
    -                    { banner_description: HTMLDescription },
    -                  ),
    -                ];
    -                stubConfig({
    -                  experience: {
    -                    experience_config: {
    -                      ...config.experience.experience_config,
    -                      ...{ translations: newExperienceTranslationsConfig },
    -                    },
    -                  },
    -                  options,
    -                });
    -              },
    -            );
    -          };
    -
    -          it("does not render HTML by default", () => {
    -            setupHTMLDescriptionTest({ allowHTMLDescription: false });
    -            cy.get("div#fides-banner").within(() => {
    -              cy.get(
    -                "div#fides-banner-description.fides-banner-description",
    -              ).contains("This test is overriding");
    -              cy.get("div#fides-banner-description.fides-banner-description")
    -                .contains("a", "clickable links")
    -                .should("not.exist");
    -            });
    -          });
    -
    -          it("renders HTML when options.allowHTMLDescription = true", () => {
    -            setupHTMLDescriptionTest({ allowHTMLDescription: true });
    -            cy.get("div#fides-banner").within(() => {
    -              cy.get(
    -                "div#fides-banner-description.fides-banner-description",
    -              ).contains("This test is overriding");
    -              cy.get("div#fides-banner-description.fides-banner-description")
    -                .contains("a", "clickable links")
    -                .should("exist");
    -            });
    -          });
    -        });
    -
    -        describe("when experience uses different descriptions for modal & banner", () => {
    -          beforeEach(() => {
    -            const bannerDescription =
    -              "This test is overriding the banner description separately from modal!";
    -            const modalDescription =
    -              "This test is overriding the modal description separately from banner!";
    -            cy.fixture("consent/fidesjs_options_banner_modal.json").then(
    -              (config) => {
    -                const newExperienceTranslationsConfig = [
    -                  overrideTranslation(
    -                    config.experience.experience_config.translations[0],
    -                    {
    -                      description: modalDescription,
    -                      banner_description: bannerDescription,
    -                    },
    -                  ),
    -                ];
    -                stubConfig({
    -                  experience: {
    -                    experience_config: {
    -                      ...config.experience.experience_config,
    -                      ...{ translations: newExperienceTranslationsConfig },
    -                    },
    -                  },
    -                });
    -              },
    -            );
    -          });
    -
    -          it("renders the expected modal & banner descriptions", () => {
    -            cy.get("div#fides-banner").within(() => {
    -              cy.get(
    -                "div#fides-banner-description.fides-banner-description",
    -              ).contains(
    -                "This test is overriding the banner description separately from modal!",
    -              );
    -            });
    -
    -            cy.contains("button", "Manage preferences").click();
    -            cy.getByTestId("consent-modal").should("be.visible");
    -
    -            cy.get("div#fides-modal").within(() => {
    -              cy.get(".fides-modal-description").contains(
    -                "This test is overriding the modal description separately from banner!",
    -              );
    -            });
    -          });
    -        });
    -      });
    -
    -      describe("titles", () => {
    -        describe("when experience uses different titles for modal & banner", () => {
    -          beforeEach(() => {
    -            const bannerTitle =
    -              "This test is overriding the banner title separately from modal!";
    -            const modalTitle =
    -              "This test is overriding the modal title separately from banner!";
    -            cy.fixture("consent/fidesjs_options_banner_modal.json").then(
    -              (config) => {
    -                const newExperienceTranslationsConfig = [
    -                  overrideTranslation(
    -                    config.experience.experience_config.translations[0],
    -                    { title: modalTitle, banner_title: bannerTitle },
    -                  ),
    -                ];
    -                stubConfig({
    -                  experience: {
    -                    experience_config: {
    -                      ...config.experience.experience_config,
    -                      ...{ translations: newExperienceTranslationsConfig },
    -                    },
    -                  },
    -                });
    -              },
    -            );
    -          });
    -
    -          it("renders the expected modal & banner title", () => {
    -            cy.get("div#fides-banner").within(() => {
    -              cy.get(".fides-banner-title")
    -                .first()
    -                .contains(
    -                  "This test is overriding the banner title separately from modal!",
    -                );
    -            });
    -
    -            cy.contains("button", "Manage preferences").click();
    -            cy.getByTestId("consent-modal").should("be.visible");
    -
    -            cy.get("div#fides-modal").within(() => {
    -              cy.get(".fides-modal-title").contains(
    -                "This test is overriding the modal title separately from banner!",
    -              );
    -            });
    -          });
    -        });
    -      });
    -
           it("can persist state between modal and banner", () => {
             cy.get("div#fides-banner").within(() => {
               cy.get("button").contains("Opt in to all").click();
    
  • clients/privacy-center/cypress/e2e/fides-js/consent-i18n.cy.ts+0 211 modified
    @@ -944,58 +944,6 @@ describe("Consent i18n", () => {
                   fixture: "experience_banner_modal.json",
                 });
               });
    -          it("applies experience language overrides", () => {
    -            const experienceTranslationOverrides = {
    -              fides_title: "My override title",
    -              fides_description: "My override description",
    -              fides_privacy_policy_url: "https://example.com/privacy",
    -              fides_override_language: "en",
    -            };
    -            cy.fixture("consent/experience_banner_modal.json").then(
    -              (experience) => {
    -                const experienceItem = experience.items[0];
    -                const translation: ExperienceConfigTranslation =
    -                  experienceItem.experience_config.translations.filter(
    -                    (i: ExperienceConfigTranslation) => i.language === "en",
    -                  )[0];
    -                stubConfig(
    -                  {
    -                    options: {
    -                      customOptionsPath: TEST_OVERRIDE_WINDOW_PATH,
    -                    },
    -                    experience: experienceItem,
    -                  },
    -                  null,
    -                  null,
    -                  undefined,
    -                  { ...experienceTranslationOverrides },
    -                );
    -                cy.get("div#fides-banner").within(() => {
    -                  cy.get(".fides-banner-title")
    -                    .first()
    -                    .contains(translation.banner_title as string);
    -                  cy.get(
    -                    "div#fides-banner-description.fides-banner-description",
    -                  ).contains(translation.banner_description as string);
    -                  cy.get("#fides-privacy-policy-link a").should(
    -                    "have.attr",
    -                    "href",
    -                    experienceTranslationOverrides.fides_privacy_policy_url,
    -                  );
    -                });
    -                // Open the modal
    -                cy.contains("button", "Manage preferences").click();
    -                cy.get("div#fides-modal").within(() => {
    -                  cy.get(".fides-modal-title").contains(
    -                    experienceTranslationOverrides.fides_title,
    -                  );
    -                  cy.get(".fides-modal-description").contains(
    -                    experienceTranslationOverrides.fides_description,
    -                  );
    -                });
    -              },
    -            );
    -          });
             });
     
             describe("when fides_override_language is only part of an experience locale string", () => {
    @@ -1006,59 +954,6 @@ describe("Consent i18n", () => {
                   fixture: "experience_banner_modal.json",
                 });
               });
    -          // TODO (PROD-1885): matchLocale needs to support partial language match
    -          it.skip("applies experience language overrides", () => {
    -            const experienceTranslationOverrides = {
    -              fides_title: "My French override title",
    -              fides_description: "My French override description",
    -              fides_privacy_policy_url: "https://example.com/privacy-french",
    -              fides_override_language: "fr",
    -            };
    -            cy.fixture("consent/experience_banner_modal.json").then(
    -              (experience) => {
    -                const experienceItem = experience.items[0];
    -                const translation: ExperienceConfigTranslation =
    -                  experienceItem.experience_config.translations.filter(
    -                    (i: ExperienceConfigTranslation) => i.language === "fr-CA",
    -                  )[0];
    -                stubConfig(
    -                  {
    -                    options: {
    -                      customOptionsPath: TEST_OVERRIDE_WINDOW_PATH,
    -                    },
    -                    experience: experienceItem,
    -                  },
    -                  null,
    -                  null,
    -                  undefined,
    -                  { ...experienceTranslationOverrides },
    -                );
    -                cy.get("div#fides-banner").within(() => {
    -                  cy.get(".fides-banner-title")
    -                    .first()
    -                    .contains(translation.banner_title as string);
    -                  cy.get(
    -                    "div#fides-banner-description.fides-banner-description",
    -                  ).contains(translation.banner_description as string);
    -                  cy.get("#fides-privacy-policy-link a").should(
    -                    "have.attr",
    -                    "href",
    -                    experienceTranslationOverrides.fides_privacy_policy_url,
    -                  );
    -                });
    -                // Open the modal
    -                cy.contains("button", "Manage preferences").click();
    -                cy.get("div#fides-modal").within(() => {
    -                  cy.get(".fides-modal-title").contains(
    -                    experienceTranslationOverrides.fides_title,
    -                  );
    -                  cy.get(".fides-modal-description").contains(
    -                    experienceTranslationOverrides.fides_description,
    -                  );
    -                });
    -              },
    -            );
    -          });
             });
     
             describe("when fides_override_language is in a locale that does not exist in experience translations", () => {
    @@ -1069,83 +964,6 @@ describe("Consent i18n", () => {
                   fixture: "experience_banner_modal.json",
                 });
               });
    -          it("does not apply experience translation overrides", () => {
    -            const experienceTranslationOverrides = {
    -              fides_title: "My override title",
    -              fides_description: "My override description",
    -              fides_override_language: "ja",
    -            };
    -            cy.fixture("consent/experience_banner_modal.json").then(
    -              (experience) => {
    -                const experienceItem = experience.items[0];
    -                // we expect to default to english translation
    -                const translation: ExperienceConfigTranslation =
    -                  experienceItem.experience_config.translations.filter(
    -                    (i: ExperienceConfigTranslation) => i.language === "en",
    -                  )[0];
    -                stubConfig(
    -                  {
    -                    options: {
    -                      customOptionsPath: TEST_OVERRIDE_WINDOW_PATH,
    -                    },
    -                    experience: experienceItem,
    -                  },
    -                  null,
    -                  null,
    -                  undefined,
    -                  { ...experienceTranslationOverrides },
    -                );
    -                cy.get("div#fides-banner").within(() => {
    -                  cy.get(".fides-banner-title")
    -                    .first()
    -                    .contains(translation.banner_title as string);
    -                  cy.get(
    -                    "div#fides-banner-description.fides-banner-description",
    -                  ).contains(translation.banner_description as string);
    -                });
    -                // Open the modal
    -                cy.contains("button", "Manage preferences").click();
    -                cy.get("div#fides-modal").within(() => {
    -                  cy.get(".fides-modal-title").contains(
    -                    translation.title as string,
    -                  );
    -                  cy.get(".fides-modal-description").contains(
    -                    translation.description as string,
    -                  );
    -                });
    -              },
    -            );
    -          });
    -          it("does apply fides_privacy_policy_url override", () => {
    -            const experienceTranslationOverrides = {
    -              fides_privacy_policy_url: "https://example.com/privacy",
    -              fides_override_language: "ja",
    -            };
    -            cy.fixture("consent/experience_banner_modal.json").then(
    -              (experience) => {
    -                const experienceItem = experience.items[0];
    -                stubConfig(
    -                  {
    -                    options: {
    -                      customOptionsPath: TEST_OVERRIDE_WINDOW_PATH,
    -                    },
    -                    experience: experienceItem,
    -                  },
    -                  null,
    -                  null,
    -                  undefined,
    -                  { ...experienceTranslationOverrides },
    -                );
    -                cy.get("div#fides-banner").within(() => {
    -                  cy.get("#fides-privacy-policy-link a").should(
    -                    "have.attr",
    -                    "href",
    -                    experienceTranslationOverrides.fides_privacy_policy_url as string,
    -                  );
    -                });
    -              },
    -            );
    -          });
             });
     
             describe("when fides_override_language is not provided", () => {
    @@ -1202,35 +1020,6 @@ describe("Consent i18n", () => {
                   },
                 );
               });
    -          it("does apply fides_privacy_policy_url override", () => {
    -            const experienceTranslationOverrides = {
    -              fides_privacy_policy_url: "https://example.com/privacy",
    -            };
    -            cy.fixture("consent/experience_banner_modal.json").then(
    -              (experience) => {
    -                const experienceItem = experience.items[0];
    -                stubConfig(
    -                  {
    -                    options: {
    -                      customOptionsPath: TEST_OVERRIDE_WINDOW_PATH,
    -                    },
    -                    experience: experienceItem,
    -                  },
    -                  null,
    -                  null,
    -                  undefined,
    -                  { ...experienceTranslationOverrides },
    -                );
    -                cy.get("div#fides-banner").within(() => {
    -                  cy.get("#fides-privacy-policy-link a").should(
    -                    "have.attr",
    -                    "href",
    -                    experienceTranslationOverrides.fides_privacy_policy_url as string,
    -                  );
    -                });
    -              },
    -            );
    -          });
             });
           });
         });
    
  • clients/privacy-center/cypress/support/stubs.ts+0 12 modified
    @@ -52,18 +52,6 @@ interface FidesConfigTesting {
       options: Partial<FidesInitOptions> | OVERRIDE;
     }
     
    -/**
    - * Helper function to override translations for Experience Configs / Notices
    - * @example overrideTranslation({language: "en", privacy_experience_config_history_id: "1342314"}, { description: "hello" })
    - */
    -export const overrideTranslation = (
    -  translation: ExperienceConfigTranslation | PrivacyNoticeTranslation,
    -  override: Partial<ExperienceConfigTranslation | PrivacyNoticeTranslation>,
    -): ExperienceConfigTranslation | PrivacyNoticeTranslation => ({
    -  ...translation,
    -  ...override,
    -});
    -
     /**
      * Helper function to swap out config
      * @example stubExperience({experience: {component: ComponentType.PRIVACY_CENTER}})
    

Vulnerability mechanics

AI mechanics synthesis has not run for this CVE yet.

References

4

News mentions

0

No linked articles in our index yet.