You can see what happens when you remove the |bash
X=oldvalue
cat <<EOF
X=world
echo "hello $X"
EOF
The $X
is replaced before piping it to bash.
You can check the following
X=oldvalue
cat <<"EOF"
X=world
echo "hello $X"
EOF
This is what you want to execute:
cat <<"EOF" | bash
X=world
echo "hello $X"
EOF