diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Revision history for pms-domain-model
 
+## 0.0.9.0 -- 2025-08-17
+
+* Fixed proc-message.
+
 ## 0.0.8.0 -- 2025-07-27
 
 * Fixed resources templates.
diff --git a/pms-domain-model.cabal b/pms-domain-model.cabal
--- a/pms-domain-model.cabal
+++ b/pms-domain-model.cabal
@@ -20,7 +20,7 @@
 -- PVP summary:     +-+------- breaking API changes
 --                  | | +----- non-breaking API additions
 --                  | | | +--- code changes with no API change
-version:            0.0.8.0
+version:            0.0.9.0
 
 -- A short (one-line) description of the package.
 synopsis:           pms-domain-model
@@ -83,6 +83,7 @@
                       bytestring,
                       filepath,
                       stm,
+                      async,
                       strip-ansi-escape,
                       safe-exceptions
                     
diff --git a/src/PMS/Domain/Model/DS/Utility.hs b/src/PMS/Domain/Model/DS/Utility.hs
--- a/src/PMS/Domain/Model/DS/Utility.hs
+++ b/src/PMS/Domain/Model/DS/Utility.hs
@@ -80,30 +80,18 @@
 --  [ ";", "&&", "|", "$", "`", "<", ">", "\\", "\"", "..", "/"]
 --
 invalidChars :: [T.Text]
-invalidChars =
-#ifdef mingw32_HOST_OS
-  [ "&&", "||", "|", ".."]
-#else
-  [ "&&", "||", "|", ".."]
-#endif
+invalidChars = [ "&&", "||", "|", "..", "reboot", "shutdown", "restart", "kill"]
 
 -- |
 --
 invalidCmds :: [String]
-invalidCmds = 
-#ifdef mingw32_HOST_OS
-  [
+invalidCmds = [
     "del", "erase", "rd", "rmdir", "format"
   , "shutdown", "restart", "taskkill"
-  ]
-#else
-  [
-    "rm", "mv", "dd", "chmod", "chown"
-  , "shutdown", "reboot", "kill", "nc"
+  , "rm", "mv", "dd", "chmod", "chown"
+  , "reboot", "kill", "nc", "sudo", "su"
   ]
-#endif
 
-
 -- |
 --
 validateMessage :: String -> IO String
@@ -164,7 +152,6 @@
     hPutStrLn stderr $ "[INFO] expect: " ++ show prompts
     output <- readUntilPrompt feed prompts
     
-    -- let result = T.unpack (TE.decodeUtf8 output)
     let result = T.unpack $ ANSI.stripAnsiEscapeCodes $ TE.decodeUtf8With TEE.lenientDecode output
     return (Just result)
 
@@ -193,16 +180,42 @@
     foundPrompt acc =
       any (`BS.isInfixOf` acc) promptBsList &&
       all (not . (`BS.isInfixOf` acc)) rejectPromptBs
+{-
+    go acc = do
+      let tout = 10*1000*1000
+      timeout tout feed >>= \case
+        Just chunk -> do
+          when ("\ESC[6n" `BS.isInfixOf` chunk) $
+            E.throwString "Unsupported: Detected cursor position report request (ESC[6n)."
 
+          let txt = TE.decodeUtf8With TEE.lenientDecode chunk
+          hPutStrLn stderr $ "[INFO] chunk:\n" ++ T.unpack txt
+
+          let acc' = BS.append acc chunk
+          if foundPrompt acc'
+            then return acc'
+            else go acc'
+        Nothing -> return $ BS.concat [BS.pack "timeout occurred. acc:", acc]
+-}
+
+
+    go :: BS.ByteString -> IO BS.ByteString
     go acc = do
-      chunk <- feed
-      when ("\ESC[6n" `BS.isInfixOf` chunk) $
-        E.throwString "Unsupported: Detected cursor position report request (ESC[6n)."
 
+      chunk <- E.catchAny feed (hdlExcept acc)
       let txt = TE.decodeUtf8With TEE.lenientDecode chunk
       hPutStrLn stderr $ "[INFO] chunk:\n" ++ T.unpack txt
 
       let acc' = BS.append acc chunk
+      when ("\ESC[6n" `BS.isInfixOf` chunk) $ do
+        let accText = TE.decodeUtf8With TEE.lenientDecode acc'
+        E.throwString $ "Unsupported: Detected cursor position report request (ESC[6n)." ++ T.unpack accText
+
       if foundPrompt acc'
         then return acc'
         else go acc'
+
+    hdlExcept :: BS.ByteString -> E.SomeException -> IO BS.ByteString
+    hdlExcept acc e = do
+      let accText = TE.decodeUtf8With TEE.lenientDecode acc
+      E.throwString $ show e ++ "\nAccumulated input so far:\n" ++ T.unpack accText
