Let me add to the previous answers for completeness. There are 2 levels to your question.
The "unchecked cast" warning is not about the types that you are trying to cast to/from. It's about the fact that there is no difference at runtime between Channel<X> and Channel<Y> due to type erasure. So a cast from one to the other will never fail at runtime even if it's wrong: it is not checked at runtime (hence the "unchecked"). This may lead to subtle bugs because you're polluting the heap.
This is different when casting non-generic types, like Any to String, or the raw part of generic types, like List<*> to MutableList<*>. Those would properly fail at runtime if the instance in question is not of the correct type.
Shouldn't this cast always be safe since Channel<out Message> can only contain objects of type Message or subclasses of type Message?
Actually no, it's not safe, as other answers have shown. The out in the declaration prevents you from sending elements into this channel (it's out-only, you can't put things in). This prevents you from inserting things that the channel cannot support. Casting would make the compiler allow that, which would be incorrect at runtime.