diff --git a/bin/freeze-score b/bin/freeze-score
index 94c0a5c28e3a1c30a5118ff9d9042347ae526f5a..f522750e805cb1ce620fd57ce9720ccdeda73801 100755
--- a/bin/freeze-score
+++ b/bin/freeze-score
@@ -7,7 +7,7 @@ from pathlib import Path
 from shutil import copyfile
 from sqlalchemy.orm import joinedload
 from typing import List
-import PyPDF2
+import pypdf
 
 import mo.db as db
 import mo.jobs.score
@@ -54,9 +54,9 @@ def download(contests: List[db.Contest], out_name: str) -> None:
 
     all_pdf = out_dir / 'all.pdf'
     print(f'Merging PDFs to {all_pdf}')
-    writer = PyPDF2.PdfWriter()
+    writer = pypdf.PdfWriter()
     for pdf in pdfs:
-        reader = PyPDF2.PdfReader(pdf)
+        reader = pypdf.PdfReader(pdf)
         for pg in reader.pages:
             writer.add_page(pg)
     with open(all_pdf, 'wb') as f:
diff --git a/constraints.txt b/constraints.txt
index 5a177a924af22ac218d55bd30caa9c12c052fdd6..c125b4cafe60deed435d5e31ce2de24d8b060a59 100644
--- a/constraints.txt
+++ b/constraints.txt
@@ -25,7 +25,7 @@ packaging==24.1
 pikepdf==9.3.0
 pillow==11.0.0
 psycopg2==2.9.10
-PyPDF2==3.0.1
+pypdf==5.4.0
 python-dateutil==2.9.0.post0
 python-magic==0.4.27
 python-poppler==0.4.1
diff --git a/mo/jobs/protocols.py b/mo/jobs/protocols.py
index bdc652d32bf287b688898f2c33e8aefd58b142c4..ce07de5170231ea6a9151fe677451841e38934c3 100644
--- a/mo/jobs/protocols.py
+++ b/mo/jobs/protocols.py
@@ -11,7 +11,7 @@ from sqlalchemy import delete
 from sqlalchemy.orm import joinedload
 from sqlalchemy.orm.query import Query
 from typing import Dict, List, Optional, Tuple
-import PyPDF2
+import pypdf
 
 import mo
 import mo.config as config
@@ -574,13 +574,13 @@ def handle_sort_scans(the_job: TheJob):
         papers[index].pages.sort(key=lambda p: p.seq_id)
 
     # Poté poskládáme výsledné PDF soubory
-    readers: Dict[int, PyPDF2.PdfReader] = {}
+    readers: Dict[int, pypdf.PdfReader] = {}
     for index in papers:
         paper = papers[index]
-        writer = PyPDF2.PdfWriter()
+        writer = pypdf.PdfWriter()
         for p in paper.pages:
             if p.file_nr not in readers:
-                readers[p.file_nr] = PyPDF2.PdfReader(job.file_path(in_files[p.file_nr]), strict=False)
+                readers[p.file_nr] = pypdf.PdfReader(job.file_path(in_files[p.file_nr]), strict=False)
             # Přihodíme správnou stránku na výstup
             pp = readers[p.file_nr].pages[p.page_nr]
             if p.rotation > 0:
diff --git a/setup.py b/setup.py
index 8d6a31d59a54724a5bca78d476ad9d27b5ec8de3..91dc036f1793f3a1d42353622a7645629f99c660 100644
--- a/setup.py
+++ b/setup.py
@@ -36,7 +36,6 @@ setuptools.setup(
         # Udržujte prosím seřazené
         'Flask',
         'Flask-WTF',
-        'PyPDF2',
         'WTForms',
         'bcrypt',
         'bleach',
@@ -50,6 +49,7 @@ setuptools.setup(
         'pikepdf',
         'pillow',
         'psycopg2',
+        'pypdf',
         'python-magic',
         'python-poppler',
         'pyzbar',