diff --git a/SOURCES/CVE-2021-20095.patch b/SOURCES/CVE-2021-20095.patch
new file mode 100644
index 0000000..f26a334
--- /dev/null
+++ b/SOURCES/CVE-2021-20095.patch
@@ -0,0 +1,128 @@
+diff --git a/babel/localedata.py b/babel/localedata.py
+index e012abb..dea0a0f 100644
+--- a/babel/localedata.py
++++ b/babel/localedata.py
+@@ -13,6 +13,8 @@
+ """
+ 
+ import os
++import re
++import sys
+ import threading
+ from itertools import chain
+ 
+@@ -22,6 +24,7 @@ from babel._compat import pickle, string_types, abc
+ _cache = {}
+ _cache_lock = threading.RLock()
+ _dirname = os.path.join(os.path.dirname(__file__), 'locale-data')
++_windows_reserved_name_re = re.compile("^(con|prn|aux|nul|com[0-9]|lpt[0-9])$", re.I)
+ 
+ 
+ def normalize_locale(name):
+@@ -38,6 +41,22 @@ def normalize_locale(name):
+             return locale_id
+ 
+ 
++def resolve_locale_filename(name):
++    """
++    Resolve a locale identifier to a `.dat` path on disk.
++    """
++
++    # Clean up any possible relative paths.
++    name = os.path.basename(name)
++
++    # Ensure we're not left with one of the Windows reserved names.
++    if sys.platform == "win32" and _windows_reserved_name_re.match(os.path.splitext(name)[0]):
++        raise ValueError("Name %s is invalid on Windows" % name)
++
++    # Build the path.
++    return os.path.join(_dirname, '%s.dat' % name)
++
++
+ def exists(name):
+     """Check whether locale data is available for the given locale.
+ 
+@@ -49,7 +68,7 @@ def exists(name):
+         return False
+     if name in _cache:
+         return True
+-    file_found = os.path.exists(os.path.join(_dirname, '%s.dat' % name))
++    file_found = os.path.exists(resolve_locale_filename(name))
+     return True if file_found else bool(normalize_locale(name))
+ 
+ 
+@@ -102,6 +121,7 @@ def load(name, merge_inherited=True):
+     :raise `IOError`: if no locale data file is found for the given locale
+                       identifer, or one of the locales it inherits from
+     """
++    name = os.path.basename(name)
+     _cache_lock.acquire()
+     try:
+         data = _cache.get(name)
+@@ -119,7 +139,7 @@ def load(name, merge_inherited=True):
+                     else:
+                         parent = '_'.join(parts[:-1])
+                 data = load(parent).copy()
+-            filename = os.path.join(_dirname, '%s.dat' % name)
++            filename = resolve_locale_filename(name)
+             with open(filename, 'rb') as fileobj:
+                 if name != 'root' and merge_inherited:
+                     merge(data, pickle.load(fileobj))
+diff --git a/tests/test_localedata.py b/tests/test_localedata.py
+index dbacba0..4730096 100644
+--- a/tests/test_localedata.py
++++ b/tests/test_localedata.py
+@@ -11,11 +11,17 @@
+ # individuals. For the exact contribution history, see the revision
+ # history and logs, available at http://babel.edgewall.org/log/.
+ 
++import os
++import pickle
++import sys
++import tempfile
+ import unittest
+ import random
+ from operator import methodcaller
+ 
+-from babel import localedata
++import pytest
++
++from babel import localedata, Locale, UnknownLocaleError
+ 
+ 
+ class MergeResolveTestCase(unittest.TestCase):
+@@ -131,3 +137,34 @@ def test_locale_identifiers_cache(monkeypatch):
+     localedata.locale_identifiers.cache = None
+     assert localedata.locale_identifiers()
+     assert len(listdir_calls) == 2
++
++
++def test_locale_name_cleanup():
++    """
++    Test that locale identifiers are cleaned up to avoid directory traversal.
++    """
++    no_exist_name = os.path.join(tempfile.gettempdir(), "babel%d.dat" % random.randint(1, 99999))
++    with open(no_exist_name, "wb") as f:
++        pickle.dump({}, f)
++
++    try:
++        name = os.path.splitext(os.path.relpath(no_exist_name, localedata._dirname))[0]
++    except ValueError:
++        if sys.platform == "win32":
++            pytest.skip("unable to form relpath")
++        raise
++
++    assert not localedata.exists(name)
++    with pytest.raises(IOError):
++        localedata.load(name)
++    with pytest.raises(UnknownLocaleError):
++        Locale(name)
++
++
++@pytest.mark.skipif(sys.platform != "win32", reason="windows-only test")
++def test_reserved_locale_names():
++    for name in ("con", "aux", "nul", "prn", "com8", "lpt5"):
++        with pytest.raises(ValueError):
++            localedata.load(name)
++        with pytest.raises(ValueError):
++            Locale(name)
diff --git a/SPECS/babel.spec b/SPECS/babel.spec
index 3104126..35432d2 100644
--- a/SPECS/babel.spec
+++ b/SPECS/babel.spec
@@ -10,13 +10,19 @@
 
 Name:           babel
 Version:        2.7.0
-Release:        10%{?dist}
+Release:        11%{?dist}
 Summary:        Tools for internationalizing Python applications
 
 License:        BSD
 URL:            http://babel.pocoo.org/
 Source0:        https://files.pythonhosted.org/packages/source/B/%{srcname}/%{srcname}-%{version}.tar.gz
 
+# Fix CVE-2021-20095: relative path traversal allows an attacker to load
+# arbitrary locale files on disk and execute arbitrary code
+# Resolved upstream: https://github.com/python-babel/babel/pull/782/
+# CVE bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1955615
+Patch1:         CVE-2021-20095.patch
+
 BuildArch:      noarch
 # Exclude i686 arch. Due to a modularity issue it's being added to the
 # x86_64 compose of CRB, but we don't want to ship it at all.
@@ -108,7 +114,7 @@ Documentation for Babel
 %endif
 
 %prep
-%autosetup -n %{srcname}-%{version}
+%autosetup -n %{srcname}-%{version} -p1
 
 %build
 %if %{with python2}
@@ -167,6 +173,10 @@ export TZ=America/New_York
 %endif
 
 %changelog
+* Wed May 12 2021 Charalampos Stratakis <cstratak@redhat.com> - 2.7.0-11
+- Fix CVE-2021-20095
+Resolves: rhbz#1955615
+
 * Fri Dec 13 2019 Tomas Orsava <torsava@redhat.com> - 2.7.0-10
 - Exclude unsupported i686 arch