diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Revision history for shortbytestring
 
+## 0.2.1.0 -- 2021-12-08
+
+* Fix memory soundness issue wrt [#4](https://github.com/hasufell/shortbytestring/issues/4)
+
 ## 0.2.0.0 -- 2021-10-31
 
 * Fix issues with CWString conversion
diff --git a/lib/Data/ByteString/Short.hs b/lib/Data/ByteString/Short.hs
--- a/lib/Data/ByteString/Short.hs
+++ b/lib/Data/ByteString/Short.hs
@@ -201,7 +201,7 @@
 snoc = \sbs c -> let l = BS.length sbs
                      nl = l + 1
   in create nl $ \mba -> do
-      copyByteArray (asBA sbs) 0 mba 0 nl
+      copyByteArray (asBA sbs) 0 mba 0 l
       writeWord8Array mba l c
 {-# INLINE snoc #-}
 
@@ -209,8 +209,9 @@
 --
 -- Note: copies the entire byte array
 cons :: Word8 -> ShortByteString -> ShortByteString
-cons c = \sbs -> let l = BS.length sbs + 1
-  in create l $ \mba -> do
+cons c = \sbs -> let l = BS.length sbs
+                     nl = l + 1
+  in create nl $ \mba -> do
       writeWord8Array mba 0 c
       copyByteArray (asBA sbs) 0 mba 1 l
 {-# INLINE cons #-}
diff --git a/lib/Data/ByteString/Short/Decode.hs b/lib/Data/ByteString/Short/Decode.hs
--- a/lib/Data/ByteString/Short/Decode.hs
+++ b/lib/Data/ByteString/Short/Decode.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE RankNTypes #-}
 
 module Data.ByteString.Short.Decode (decodeUtf16LE, decodeUtf16LEWith, decodeUtf16LE', decodeUtf16LE'', decodeUtf8, decodeUtf8With, decodeUtf8') where
@@ -15,9 +16,13 @@
 import Data.Text.Internal.Fusion.Size
     ( maxSize )
 import Data.Text.Internal.Unsafe.Char
+#if MIN_VERSION_text(2,0,0)
+    ( unsafeChr16, unsafeChr8 )
+#else
     ( unsafeChr, unsafeChr8 )
-import Data.Text.Internal.Unsafe.Shift
-    ( shiftL, shiftR )
+#endif
+import Data.Bits
+    ( unsafeShiftL, unsafeShiftR )
 import Data.Word
     ( Word16, Word8 )
 
@@ -31,6 +36,9 @@
 import GHC.IO
     ( unsafeDupablePerformIO )
 
+#if !MIN_VERSION_text(2,0,0)
+unsafeChr16 = unsafeChr
+#endif
 
 -- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using UTF-8
 -- encoding.
@@ -56,18 +64,18 @@
 -- | /O(n)/ Convert a 'ShortByteString' into a 'Stream Char', using little
 -- endian UTF-16 encoding.
 streamUtf16LE :: OnDecodeError -> ShortByteString -> Stream Char
-streamUtf16LE onErr bs = Stream next 0 (maxSize (l `shiftR` 1))
+streamUtf16LE onErr bs = Stream next 0 (maxSize (l `unsafeShiftR` 1))
     where
       l = BS.length bs
       {-# INLINE next #-}
       next i
           | i >= l                         = Done
-          | i+1 < l && U16.validate1 x1    = Yield (unsafeChr x1) (i+2)
+          | i+1 < l && U16.validate1 x1    = Yield (unsafeChr16 x1) (i+2)
           | i+3 < l && U16.validate2 x1 x2 = Yield (U16.chr2 x1 x2) (i+4)
           | otherwise = decodeError "streamUtf16LE" "UTF-16LE" onErr Nothing (i+1)
           where
-            x1    = idx i       + (idx (i + 1) `shiftL` 8)
-            x2    = idx (i + 2) + (idx (i + 3) `shiftL` 8)
+            x1    = idx i       + (idx (i + 1) `unsafeShiftL` 8)
+            x2    = idx (i + 2) + (idx (i + 3) `unsafeShiftL` 8)
             idx = fromIntegral . BS.index bs :: Int -> Word16
 {-# INLINE [0] streamUtf16LE #-}
 
diff --git a/lib/Data/ByteString/Short/Internal.hs b/lib/Data/ByteString/Short/Internal.hs
--- a/lib/Data/ByteString/Short/Internal.hs
+++ b/lib/Data/ByteString/Short/Internal.hs
@@ -268,8 +268,9 @@
   case (# indexWord8Array# ba# i#, indexWord8Array# ba# (i# +# 1#) #) of
     (# lsb#, msb# #) -> W16# ((decodeWord16LE# (# lsb#, msb# #)))
 
+#if !MIN_VERSION_base(4,16,0)
 
-encodeWord16LE# :: Word# -- ^ Word16
+encodeWord16LE# :: Word#              -- ^ Word16
                 -> (# Word#, Word# #) -- ^ Word8 (LSB, MSB)
 encodeWord16LE# x# = (# (x# `and#` int2Word# 0xff#)
                      ,  ((x# `and#` int2Word# 0xff00#) `shiftRL#` 8#) #)
@@ -278,4 +279,19 @@
                 -> Word#              -- ^ Word16
 decodeWord16LE# (# lsb#, msb# #) = ((msb# `shiftL#` 8#) `or#` lsb#)
 
+#else
 
+encodeWord16LE# :: Word16#              -- ^ Word16
+                -> (# Word8#, Word8# #) -- ^ Word8 (LSB, MSB)
+encodeWord16LE# x# = (# word16ToWord8# x#
+                     ,  word16ToWord8# (x# `uncheckedShiftRLWord16#` 8#) #)
+  where
+    word16ToWord8# y = wordToWord8# (word16ToWord# y)
+
+decodeWord16LE# :: (# Word8#, Word8# #) -- ^ Word8 (LSB, MSB)
+                -> Word16#              -- ^ Word16
+decodeWord16LE# (# lsb#, msb# #) = ((word8ToWord16# msb# `uncheckedShiftLWord16#` 8#) `orWord16#` word8ToWord16# lsb#)
+  where
+    word8ToWord16# y = wordToWord16# (word8ToWord# y)
+
+#endif
diff --git a/lib/Data/ByteString/Short/Word16.hs b/lib/Data/ByteString/Short/Word16.hs
--- a/lib/Data/ByteString/Short/Word16.hs
+++ b/lib/Data/ByteString/Short/Word16.hs
@@ -221,7 +221,7 @@
 snoc = \(assertEven -> sbs) c -> let l = BS.length sbs
                                      nl = l + 2
   in create nl $ \mba -> do
-      copyByteArray (asBA sbs) 0 mba 0 nl
+      copyByteArray (asBA sbs) 0 mba 0 l
       writeWord16Array mba l c
 {-# INLINE snoc #-}
 
@@ -233,7 +233,7 @@
                                      nl = l + 2
   in create nl $ \mba -> do
       writeWord16Array mba 0 c
-      copyByteArray (asBA sbs) 0 mba 2 nl
+      copyByteArray (asBA sbs) 0 mba 2 l
 {-# INLINE cons #-}
 
 -- | /O(1)/ Extract the last element of a ShortByteString, which must be finite and at least one Word16.
diff --git a/shortbytestring.cabal b/shortbytestring.cabal
--- a/shortbytestring.cabal
+++ b/shortbytestring.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               shortbytestring
-version:            0.2.0.0
+version:            0.2.1.0
 license:            MIT
 license-file:       LICENSE
 maintainer:         hasufell@posteo.de
@@ -40,7 +40,7 @@
     , exceptions        ^>=0.10
     , primitive         ^>=0.7
     , template-haskell  >=2.10     && <2.20
-    , text              >=1.2.3.0  && <1.2.6
+    , text              >=1.2.3.0  && <2.1
     , word16
     , word8             ^>=0.1
 
