It detected the Quality Gate as intended and failed as intended. I need a way to force abort this job if the quality gate failed (without using the withSonarQubeEnv and waitForQualityGate).
Issue resolved. Apparently, Jenkins shell command always retrieve the last command as the exit code. In my case, after running the Sonar Scanner, I tried to echo something. The echo command is being took in as the success exit code instead of the Sonar Scanner failure exit code. Hope this helps people who face the similar situation in future.