diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1826ab5212edaff7896e2600db14bdc63688c637..044975b19b4fdcf313072b046341311cb0614f49 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,6 +64,7 @@ if(NOT MSVC AND NOT CLANG_TIDY_WORKAROUND)
 		"${CMAKE_CXX_FLAGS} \
 		-Wall \
 		-Wextra \
+		-Wconversion \
 		-pipe \
 		-pedantic \
 		-fsized-deallocation \
diff --git a/lib/crypto/client.cpp b/lib/crypto/client.cpp
index fd987a9437b7c76ddde6ab960a6d9662f9c35e19..5a9bba8cc366c48a2ca7a17c4b6a98809be69743 100644
--- a/lib/crypto/client.cpp
+++ b/lib/crypto/client.cpp
@@ -916,8 +916,9 @@ mtx::crypto::encrypt_exported_sessions(const mtx::crypto::ExportedSessionKeys &k
 {
     const auto plaintext = json(keys).dump();
 
-    auto nonce = create_buffer(AES_BLOCK_SIZE);
-    nonce[15 - 63 % 8] &= ~(1UL << (63 / 8));
+    auto nonce                  = create_buffer(AES_BLOCK_SIZE);
+    constexpr std::uint8_t mask = static_cast<std::uint8_t>(~(1U << (63 / 8)));
+    nonce[15 - 63 % 8] &= mask;
 
     auto salt = create_buffer(pwhash_SALTBYTES);
 
diff --git a/lib/crypto/encoding.cpp b/lib/crypto/encoding.cpp
index 90a1ae445d31a6b73a6a4c657cbb5448014edc7a..f6b1701c910b085d38e941decd771129bcf28442 100644
--- a/lib/crypto/encoding.cpp
+++ b/lib/crypto/encoding.cpp
@@ -186,16 +186,16 @@ decode_base64(const std::array<uint8_t, 256> &reverse_alphabet, const std::strin
             decoded.push_back(static_cast<char>(d << 2));
             break;
         case 1:
-            decoded.back() += (d >> 4);
+            decoded.back() = static_cast<char>(decoded.back() + (d >> 4));
             decoded.push_back(static_cast<char>(d << 4));
             break;
         case 2:
-            decoded.back() += (d >> 2);
+            decoded.back() = static_cast<char>(decoded.back() + (d >> 2));
             decoded.push_back(static_cast<char>(d << 6));
             break;
         case 3:
-            decoded.back() += d;
-            bit_index = 0;
+            decoded.back() = static_cast<char>(decoded.back() + d);
+            bit_index      = 0;
         }
     }
 
diff --git a/lib/crypto/utils.cpp b/lib/crypto/utils.cpp
index c0ef346612f31004ed4d232dfa5302c8653ed2de..9cf2020385c2657364b3ff463f1506355d6703a9 100644
--- a/lib/crypto/utils.cpp
+++ b/lib/crypto/utils.cpp
@@ -215,8 +215,9 @@ compatible_iv(BinaryBuf incompatible_iv)
     // the last byte. So we need to clear byte 15 - 63%8 = 15 - 7 = 8, the highest bit, 1 << 7
     // see:
     // https://github.com/matrix-org/matrix-js-sdk/blob/529fe93ab14b93c515e9ab0d0277c1942a5d73c5/src/crypto/aes.ts#L144
-    uint8_t *data = incompatible_iv.data();
-    data[15 - 63 % 8] &= ~(1UL << (63 / 8));
+    uint8_t *data               = incompatible_iv.data();
+    constexpr std::uint8_t mask = static_cast<std::uint8_t>(~(1U << (63 / 8)));
+    data[15 - 63 % 8] &= mask;
     return incompatible_iv;
 }
 
@@ -233,7 +234,7 @@ AES_CTR_256_Encrypt(const std::string &plaintext, const BinaryBuf &aes256Key, Bi
     BinaryBuf encrypted = compatible_iv(create_buffer(plaintext.size() + AES_BLOCK_SIZE));
 
     /* Create and initialise the context */
-    if (!(ctx = EVP_CIPHER_CTX_new())) {
+    if (ctx = EVP_CIPHER_CTX_new(); !ctx) {
         // handleErrors();
     }
 
@@ -281,7 +282,7 @@ AES_CTR_256_Decrypt(const std::string &ciphertext, const BinaryBuf &aes256Key, B
     BinaryBuf decrypted = create_buffer(ciphertext.size());
 
     /* Create and initialise the context */
-    if (!(ctx = EVP_CIPHER_CTX_new())) {
+    if (ctx = EVP_CIPHER_CTX_new(); !ctx) {
         // handleErrors();
     }
 
@@ -489,9 +490,10 @@ encrypt_file(const std::string &plaintext)
     mtx::crypto::EncryptedFile encryption_info;
 
     // iv has to be 16 bytes, key 32!
-    BinaryBuf key = create_buffer(32);
-    BinaryBuf iv  = create_buffer(16);
-    iv[15 - 63 % 8] &= ~(1UL << (63 / 8));
+    BinaryBuf key               = create_buffer(32);
+    BinaryBuf iv                = create_buffer(16);
+    constexpr std::uint8_t mask = static_cast<std::uint8_t>(~(1U << (63 / 8)));
+    iv[15 - 63 % 8] &= mask;
 
     // Counter should be 0 in v1.1 of the spec...
     for (int i = 8; i < 16; i++)
diff --git a/lib/http/client.cpp b/lib/http/client.cpp
index 954fcb8b5ed4f2de0a39bcd0806108efbfa63928..f9847d55385c8cdc5d4dbcff4b24e01c795eddb4 100644
--- a/lib/http/client.cpp
+++ b/lib/http/client.cpp
@@ -160,7 +160,7 @@ void
 Client::set_server(const std::string &server)
 {
     std::string_view server_name = server;
-    int port                     = 443;
+    std::uint16_t port           = 443;
     this->protocol_              = "https";
     // Remove https prefix, if it exists
     if (server_name.substr(0, 8) == "https://") {
@@ -181,7 +181,7 @@ Client::set_server(const std::string &server)
 
         auto tmp = std::string(server_name.substr(colon_offset + 1));
         if (mtx::client::utils::is_number(tmp)) {
-            port_ = std::stoi(tmp);
+            port_ = static_cast<std::uint16_t>(std::stoul(tmp));
             return;
         }
     }
diff --git a/tests/test_helpers.hpp b/tests/test_helpers.hpp
index 8e039e7635767cd806751b54077de19c4a0d5ff3..2a7ea19de3ca4e23c56f78fb582ce9f38e8b091c 100644
--- a/tests/test_helpers.hpp
+++ b/tests/test_helpers.hpp
@@ -15,10 +15,8 @@
 inline int
 random_number()
 {
-    std::mt19937 rng;
-    rng.seed(std::random_device()());
-    std::uniform_int_distribution<std::mt19937::result_type> dist(1,
-                                                                  std::numeric_limits<int>::max());
+    std::random_device rng;
+    std::uniform_int_distribution<int> dist(1, std::numeric_limits<int>::max());
 
     return dist(rng);
 }