DEV Community

Oli
Oli

Posted on

Spotting GPS spoofing on a drone — and flying on when the signal is gone

Follow-up to my MAVLink post. Same caveat: I'm a beginner doing this as a hobby. The results below come from two small experiments in ArduPilot SITL on a simple setup, so please don't read too much into the exact numbers.

The weak link: a GPS that believes everything

We secure the comms, encrypt the telemetry… and often forget the drone has another vital sense that's just as exposed: GPS.

The issue is structural. Civilian GPS isn't authenticated — the receiver has no cryptographic way to check that the signals really come from satellites. So two attacks target it:

  • Spoofing: broadcasting fake navigation signals, stronger than the real ones, so the drone thinks it's somewhere it isn't.
  • Denial (jamming): drowning the GPS band to blind the drone entirely.

This isn't hypothetical: ships have reported impossible positions at sea, airliners have hit spoofing near conflict zones, and anti-drone "bubbles" exist around sensitive sites. The gear to spoof GPS reportedly costs only a few hundred euros now.

Two problems, two answers: detect the attack, and survive even when you don't.

Part 1 — Catching the liar

You can't verify the GPS signal itself (no authentication). But you can check its consistency with everything else the drone senses.

A modern drone doesn't rely on GPS alone: it runs an Extended Kalman Filter (EKF) that fuses the accelerometer, gyro, barometer, etc., and continuously predicts where it should be. If the GPS position matches the prediction, fine. If it suddenly diverges… that's suspicious.

To quantify "diverge," I used the Mahalanobis distance. Instead of a raw distance in metres, it measures how many standard deviations the GPS reading is from the prediction, weighted by the filter's uncertainty (its covariance). That's the appealing part: tolerate normal GPS noise, but flag a statistically abnormal jump. A simple threshold can trigger the alarm.

And for the clever attacker who slowly drifts the position to stay under the radar? I added a CUSUM test (cumulative sum), which catches a small systematic drift building up over time that an instantaneous threshold would miss.

What I saw in my test

In SITL, drone hovering, I injected fake GPS coordinates. The result was quite visual: the Mahalanobis distance stayed flat while things were normal, then spiked right at the moment of injection. A SPOOF DETECTED alert fired and the failsafe took over. In my (limited) runs I didn't see false positives — but my setup was simple and the scenario clean, so I wouldn't generalise from that.

The nice part is it runs without extra hardware: it reuses the EKF already in the autopilot. No multi-antenna receiver, no atomic clock — just statistics on data you already have. (Real anti-spoofing systems are far more sophisticated; this is very much a learner's version of the idea.)

Part 2 — Surviving with no GPS

Detection is nice. But what if you miss it, or it's pure jamming — no signal at all? The drone still has to stay in control.

First building block, already in the autopilot: dead reckoning. From the IMU alone, ArduPilot keeps flying for a few seconds after GPS loss, then heads home. The snag: dead reckoning drifts — without an external reference, position error piles up fast.

Second block, to bound that drift: optical flow. A small (~€25) sensor that looks at the ground and measures actual movement, a bit like an optical mouse. Fused into the EKF, it gives a motion reference that needs no satellite.

What I measured

I compared three scenarios in SITL, drone flying, then GPS cut:

Scenario Max drift Mode after cut
A — Normal GPS (baseline) 0.02 m normal flight
B — GPS lost, no defense 0.67 m emergency landing
C — GPS lost + optical flow 0.15 m emergency landing

An honest reading: without GPS, the drone triggers an emergency landing in both cases — optical flow does not give "free" GPS-denied flight. What it does, and it's already a lot, is cut the drift by roughly 4x (0.67 m → 0.15 m) during that descent, so the drone lands where it is rather than ~70 cm away in the wind. And again — tiny experiment, simulation only, don't over-trust the figure.

The way I'd put it: dead reckoning drifts, but it's better than nothing — enough for the drone to at least head home. I'd rather state that plainly than oversell an "autonomous no-GPS flight" my data doesn't show.

On the ArduPilot side, the gist is three parameters: enable optical flow (FLOW_TYPE), a rangefinder for altitude (RNGFND1_TYPE), and the dead-reckoning failsafe (FS_DR_ENABLE), with GPS staying the EKF's primary source while it's healthy.

Same flaw, two strategies

Stepping back, GPS spoofing and MAVLink command injection seem to share the same root cause: an input the system accepts without being able to authenticate it.

  • When you control the channel (telemetry), you go for prevention: signing + encryption.
  • When you don't (GPS, which you can't control), you go for detection + resilience: spot the inconsistency, and stay in control even if detection fails.

That, as I understand it, is defense in depth on a drone: planning for your own defenses to fail.

Takeaways (beginner edition)

GPS isn't a source of truth, it's just one more sensor — and one you can't authenticate. So cross-check it against your internal estimate, and plan for the worst, i.e. flying without it.

Good news: most of these protections (EKF, dead-reckoning failsafe, optical-flow support) are already in ArduPilot. The work is enabling, tuning and testing them — not reinventing the wheel. I'm still very much in the testing-and-learning phase, so corrections are welcome.


Happy to share more detail in the comments.

Top comments (0)