Am I compromising effiency by using CTE instead of indexed tables? Consider scenario where I am creating multiple intermediate tables in CTEs before joining the last intermediate result to some other table. The intermediate results can use joines as well. 

The alternative is that I rewrite the code so that each intermediate CTE gets its own table with clustered index on columns required for efficient subsequent joins. I would expect queries on tables with indexes to perform faster. 

I understand the intermediate CTE results are written to disk anyway, so I/O constraints should not be considered here, right?

Let’s assume we are considering joining tables with 50m-500m of rows in SQL Server.
A CTE is just a disposable view. As Erik commented, CTE results are not stored to disk.

In terms of perf, a temp table has many advantages of creating indexes, stats, etc which will outperform CTE when dealing with large tables and complex queries.

When we migrated from sql server 2008 to 2014 (SP2+CU8), I saw queries performing poor (generating bad query plans) and we had to change them to use temp tables.

So - based on my experience - if you need speed, go with temp tables (they are not free as depending on how much data you are dealing with, it hits temp table and memory).

Read Martin's answer at : Which are more performant, CTE or temporary tables?