A walk through a real embedded penetration test, step by step.
A test plan checks the cases you thought of. Fuzzing finds the ones you didn't, and in embedded automotive code, the ones you didn't think of are usually the ones that crash.
Fuzz testing means automatically feeding a system malformed or unexpected inputs and watching for crashes, hangs and other weaknesses. Instead of a fixed list of test vectors, a fuzzer generates a huge, varied stream of inputs and lets the target tell you which ones break it.
Why it beats a hand-written test plan
A test plan encodes expected behaviour, so it exercises the paths a developer already understands. Modern coverage-guided fuzzers do the opposite: they watch which code paths each input reaches and steer toward inputs that reach new ones. That is how they surface the parser edge cases, integer overflows and memory-safety faults that no one wrote a test for.
Where it fits in a vehicle
The high-value targets are the places that parse untrusted input: CAN and UDS message handlers, diagnostic services, bootloaders, and the code that unpacks an OTA update. Anything that takes bytes from outside the ECU and interprets them is worth fuzzing.
Making it practical
- Instrument the target so the fuzzer can see coverage, or fuzz the parser as a harness on the host.
- Seed it with real, valid messages so it starts from meaningful structure.
- Run it continuously in CI, not once before release, new code means new paths.
- Triage every crash: reproduce, find the root cause, fix the class of bug, not just the input.
Fuzzing complements penetration testing rather than replacing it. If you want to see where it would pay off on your ECUs, start with a gap assessment.