I feel that most 100K line programs could be rewritten with just 10K lines and end up being more reliable.
Feature creep is responsible for some of the code bloat but I can guarantee from experience that, in the vast majority of projects, you could keep all the features and still cut the code to at least 1/10th of its size.
I think the reason for this is because developers who focus on development speed do so at the expense of succinctness. The more foresight you have when you're writing code, the fewer lines you will end up with. Unfortunately, developing that foresight requires time spent not coding; it means choosing the best option out of all viable alternatives. When developers are pressed for time, even if LOC is not used as a metric to judge them, they will not have the time to look ahead in the near future to minimize the lines of code.
Workarounds tend to require a lot of lines. When code is rushed, it ends up getting littered with workarounds which require additional checks, additional tests, etc... A bad foundation with sub-optimal abstractions can force developers' hands and lead to even more bad code being produced on top.
Before I start working on a feature, I simulate how it's going to work in my head and try to identify all the hurdles and alternatives; sometimes several levels down in the hypothetical component/module hierarchy. I do brainstorms, draw diagrams and make lists of pros-and-cons. I use as many visual aids as I can get. I play devil's advocate with my own ideas until I'm at my mental limit and I cannot visualize the solution (and requirements) in any more detail and cannot identify any other hurdles. It actually feels like playing chess. You need a strong understanding of your tools and environment to be able to do do this kind of adversarial brainstorming and most importantly, you need time. Especially in the early stages of the project. The further along you are in the project, the less foresight you need.