diff --git a/docs/news.rst b/docs/news.rst
index 4961729..2fbe136 100644
--- a/docs/news.rst
+++ b/docs/news.rst
@@ -4,6 +4,7 @@ Release Notes
 **UNRELEASED**
 
 - Updated vendored ``packaging`` to 23.0
+- ``wheel unpack`` now preserves the executable attribute of extracted files
 - Fixed spaces in platform names not being converted to underscores (PR by David Tucker)
 - Fixed ``RECORD`` files in generated wheels missing the regular file attribute
 - Fixed ``DeprecationWarning`` about the use of the deprecated ``pkg_resources`` API
diff --git a/src/wheel/cli/unpack.py b/src/wheel/cli/unpack.py
index c6409d4..d48840e 100644
--- a/src/wheel/cli/unpack.py
+++ b/src/wheel/cli/unpack.py
@@ -18,6 +18,13 @@ def unpack(path: str, dest: str = ".") -> None:
         namever = wf.parsed_filename.group("namever")
         destination = Path(dest) / namever
         print(f"Unpacking to: {destination}...", end="", flush=True)
-        wf.extractall(destination)
+        for zinfo in wf.filelist:
+            wf.extract(zinfo, destination)
+
+            # Set permissions to the same values as they were set in the archive
+            # We have to do this manually due to
+            # https://github.com/python/cpython/issues/59999
+            permissions = zinfo.external_attr >> 16 & 0o777
+            destination.joinpath(zinfo.filename).chmod(permissions)
 
     print("OK")

diff --git a/tests/cli/test_unpack.py b/tests/cli/test_unpack.py
index e6a38bb..ae584af 100644
--- a/tests/cli/test_unpack.py
+++ b/tests/cli/test_unpack.py
@@ -1,6 +1,12 @@
 from __future__ import annotations
 
+import platform
+import stat
+
+import pytest
+
 from wheel.cli.unpack import unpack
+from wheel.wheelfile import WheelFile
 
 
 def test_unpack(wheel_paths, tmp_path):
@@ -10,3 +16,21 @@ def test_unpack(wheel_paths, tmp_path):
     """
     for wheel_path in wheel_paths:
         unpack(wheel_path, str(tmp_path))
+
+
+@pytest.mark.skipif(
+    platform.system() == "Windows", reason="Windows does not support the executable bit"
+)
+def test_unpack_executable_bit(tmp_path):
+    wheel_path = tmp_path / "test-1.0-py3-none-any.whl"
+    script_path = tmp_path / "script"
+    script_path.write_bytes(b"test script")
+    script_path.chmod(0o755)
+    with WheelFile(wheel_path, "w") as wf:
+        wf.write(str(script_path), "nested/script")
+
+    script_path.unlink()
+    script_path = tmp_path / "test-1.0" / "nested" / "script"
+    unpack(str(wheel_path), str(tmp_path))
+    assert not script_path.is_dir()
+    assert stat.S_IMODE(script_path.stat().st_mode) == 0o755

wheel unpack doesn't preserve permissions
I expected `wheel unpack` + `wheel pack` to result in similarly functioning wheels. However, `wheel unpack` doesn't seem to preserve permissions. That is, there's nothing in `wheel` that does this kind of thing: https://github.com/pypa/pip/blob/852deddb9c14afdb780e77ea28c2fa6d29f8c2e1/src/pip/_internal/utils/unpacking.py#L143 

Is this intentional?
tests/cli/test_unpack.py::test_unpack_executable_bit
tests/cli/test_unpack.py::test_unpack