IMO, anything user-facing tends to be more complicated than intuition suspects.
User input doesn't follow design contracts.
Example:
Maybe you have a regular expression engine in the back-end. It's sometimes possible to craft an input which causes such an engine to break.
Try to run this Perl code
1 2 3 4
|
#!/bin/perl
print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" =~
("a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?".
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
|
The code above tries to match the string
"aaaa....aaaa" against
"a?a?....a?a?aaaa...aaaa".
You'll be waiting forever, or close to it (it takes exponential time). Fundamentally this is not necessary: there's a well-known linear time algorithm that could work for the above, but PCREs support features for which a fast algorithm probably doesn't exist (i.e., backreferences -- the problem's NP-complete).
Now if you ever want to process user-input with PCREs, or more directly, take a regular expression as input, you have to make sure that you'll never run a query like this. Tricky!
Also, Moravec's paradox:
https://en.wikipedia.org/wiki/Moravec%27s_paradox