Another approach, which would seem even safer than the 'async assert/sync release' approach, would be to have an asynchronous reset detector (much as described elsewhere, with asynchronous 'assert' and synchronous 'release'), but have the output from that gate any outward-facing I/O devices without asynchronously resetting anything (other than the latch in the detector itself). If one uses two asynchronous reset detectors, one for I/O lines and one to feed the synchronous reset detector, and if one designs the one for I/O lines so that it will only be tripped by reset pulses which are sound enough to reliably trip the main detector, one may avoid even having the outputs glitch in cases that aren't going to reset the CPU. Note that if one does this, a legitimate-length reset pulse will reset the outputs asynchronously, but a runt reset pulse may not cleanly reset the outputs until two clock cycles later (if the runt reset pulse is followed by a real one before two clocks have arrived, the real reset pulse will reset the outputs even if the runt pulse didn't).
Another thing to consider is that systems often have some registers which are not supposed to be affected by a reset. If an asynchronous reset could hit circuitry which writes to those registers, it would be possible for a reset pulse which arrives at the wrong time to clobber those registers, even if it's a clean (non-runt) pulse. For example, if code is trying to write to address 1111 and an async reset which arrives just before a clock pulse forces one of the address latches to zero just as the clock pulse is arriving, that could cause an erroneous write to address 1110. While one could use multiple internal reset lines with combinatorial delays to ensure that register writes were disabled before the address got clobbered, using synchronous internal reset logic avoids the issue altogether.
BTW, here's a circuit illustrating the concept. Near the lower-left corner are two logic inputs for reset. One will generate a "clean" reset pulse, and the other will generate a really icky one. The yellow LED indicates main system reset; the cyan LED indicates I/O enable. Hitting a clean reset will cause an immediate "reset" of the outputs; hitting an icky reset will either cause a delayed reset of the outputs, or leave them unaffected (in the simulator, there's no way to cause the 'leave them unaffected' case).