diff --git a/CMakeLists.txt b/CMakeLists.txt
index ad3fb24318d1b2dfe774ebb7de4b01b9a619801c..6c466dcd18061fcda52649e6bb44a5fa9800ae55 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -61,7 +61,6 @@ include(CPM)
 CPMAddPackage(
   NAME units
   GITHUB_REPOSITORY nholthaus/units
-  GIT_TAG v2.3.3
   VERSION 2.3.3
   PATCH_COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/patches/units/pascal-name-conflict.patch || true
   OPTIONS "DISABLE_PREDEFINED_UNITS ON"
@@ -87,7 +86,10 @@ add_library(MantleAPI::MantleAPI ALIAS MantleAPI)
 target_link_libraries(MantleAPI INTERFACE units::units)
 
 include(GNUInstallDirs)
-set(INSTALL_CONFIG_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/MantleAPI")
+set(MantleAPI_INSTALL_CONFIG_DIR
+    "${CMAKE_INSTALL_LIBDIR}/cmake/MantleAPI"
+    CACHE STRING "Installation directory for CMake package config files"
+)
 
 target_include_directories(
   MantleAPI INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
@@ -115,7 +117,7 @@ endif()
 include(CMakePackageConfigHelpers)
 configure_package_config_file(
   "${PROJECT_SOURCE_DIR}/cmake/MantleAPIConfig.cmake.in" "${PROJECT_BINARY_DIR}/MantleAPIConfig.cmake"
-  INSTALL_DESTINATION ${INSTALL_CONFIG_DIR}
+  INSTALL_DESTINATION ${MantleAPI_INSTALL_CONFIG_DIR}
   PATH_VARS CMAKE_INSTALL_INCLUDEDIR
 )
 
@@ -132,13 +134,13 @@ if(MantleAPI_INSTALL)
 
   install(
     EXPORT MantleAPITargets
-    DESTINATION ${INSTALL_CONFIG_DIR}
+    DESTINATION ${MantleAPI_INSTALL_CONFIG_DIR}
     NAMESPACE MantleAPI::
   )
 
   install(
     FILES "${PROJECT_BINARY_DIR}/MantleAPIConfig.cmake" "${PROJECT_BINARY_DIR}/MantleAPIConfigVersion.cmake"
-    DESTINATION ${INSTALL_CONFIG_DIR}
+    DESTINATION ${MantleAPI_INSTALL_CONFIG_DIR}
     COMPONENT dev
   )
 endif()
diff --git a/README.md b/README.md
index d15a6cdf6440114710cab70719ca9d4025c2cbac..e2c955b9e1440d14bc4eb0978e266e153997e990 100644
--- a/README.md
+++ b/README.md
@@ -170,7 +170,7 @@ In the following a course guideline is given, when to increment the according fi
 
 | Name                                                               | License      | Version |
 |--------------------------------------------------------------------|--------------|---------|
-| [CPM](https://github.com/cpm-cmake/CPM.cmake)                      | MIT          | 0.36.0  |
+| [CPM](https://github.com/cpm-cmake/CPM.cmake)                      | MIT          | 0.40.2  |
 | [Doxygen Awesome](https://github.com/jothepro/doxygen-awesome-css) | MIT          | 2.3.1   |
 | [GoogleTest](https://github.com/google/googletest)                 | BSD-3-Clause | 1.12.1  |
 | [Units](https://github.com/nholthaus/units)                        | MIT          | 2.3.3   |
diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake
index 772103fc337e48eb1ecb4e978782fea3766fd35d..baf2d8c344af8dcf5ef69bb7db84aa551fb74ec0 100644
--- a/cmake/CPM.cmake
+++ b/cmake/CPM.cmake
@@ -1,4 +1,9 @@
-set(CPM_DOWNLOAD_VERSION 0.36.0)
+# SPDX-License-Identifier: MIT
+#
+# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
+
+set(CPM_DOWNLOAD_VERSION 0.40.2)
+set(CPM_HASH_SUM "c8cdc32c03816538ce22781ed72964dc864b2a34a310d3b7104812a5ca2d835d")
 
 if(CPM_SOURCE_CACHE)
   set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
@@ -10,12 +15,10 @@ endif()
 
 # Expand relative path. This is important if the provided path contains a tilde (~)
 get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
-if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
-  message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
-  file(DOWNLOAD
-       https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
-       ${CPM_DOWNLOAD_LOCATION}
-  )
-endif()
+
+file(DOWNLOAD
+     https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
+     ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
+)
 
 include(${CPM_DOWNLOAD_LOCATION})