The danger of powerful generality, illustrated
When you are coding the framework for a web application, there is a lot of annoying component registration boilerplate. It is tempting to get rid of the boilerplate by using some introspection-based abstraction, and in some ways it's the right thing to do; 'don't repeat yourself' is one of the tenets of modern programming.
When you do this, it's tempting to make it straightforwardly file-based. For example, a web application with various operations could work by having the framework work out the operation for each request, then attempting to load a file of the same name from a directory somewhere. To add a new operation, just code up all of the necessary routines in an appropriately named file in the directory and you're done, with no additional configuration needed. General, powerful, easy to use, what could be better?
Then some joker on the Internet sends you a HTTP request that specifies an operation of '../../../../proc/self/environ%00', and your framework dutifully goes off, uses it as the filename to look up, loads the file, and does something useful (for the attacker) with it.
The problem (or one of the problems) is that it is too easy to be too general this way. You don't really want to use arbitrary files, you want to restrict it to just files in a specific directory, but to do this takes extra code, and to write the extra code you have to realize that the vulnerability exists in the first place.
(One might think that people would never make this mistake, but our web server logs strongly suggest otherwise; we've been getting a bunch of (failed) requests like this lately. The ones we've seen give the operation as a query parameter.)