AuthonAuthon Blog
debugging6 min read

How to Stop Your App from Leaking User Locations (Yes, It Matters)

How to prevent location data leaks in your apps — practical code examples for truncating GPS data, enforcing privacy zones, and making privacy the default.

AW
Alan West
Authon Team
How to Stop Your App from Leaking User Locations (Yes, It Matters)

So Le Monde just tracked France's aircraft carrier — in real time — using publicly available fitness app data. Soldiers on board were logging runs on the flight deck, and that location data was accessible to anyone who knew where to look.

If you're a developer and that doesn't make you sweat a little, you might want to re-read it. Because the same class of vulnerability exists in a shocking number of apps we build every day.

This isn't a military problem. It's a data exposure problem. And it's one we can actually fix in code.

The Root Cause: Location Data Is Treated as Non-Sensitive

Here's the core issue. Most apps request location permissions, collect GPS coordinates, and then treat those coordinates like any other piece of data — stored in plain text, synced to APIs, sometimes even exposed in public-facing endpoints.

The Strava situation (and similar incidents going back to 2018) happens because:

  • GPS coordinates are collected at high precision when the app only needs low precision
  • Activity data is public by default instead of private by default
  • Aggregated location data creates patterns that reveal sensitive information even when individual points seem harmless
  • There's no server-side enforcement of privacy zones — it's all client-side and optional
  • Let me walk through how to actually address each of these in your own projects.

    Step 1: Request the Minimum Location Precision You Actually Need

    Most apps don't need to know that a user is at 48.8566° N, 2.3522° E. They need to know the user is in Paris.

    If you're building for the web, the Geolocation API lets you specify this:

    javascript
    // Bad: requesting high accuracy when you don't need it
    navigator.geolocation.getCurrentPosition(callback, error, {
      enableHighAccuracy: true // gives you GPS-level precision
    });
    
    // Better: let the device use low-power, coarse location
    navigator.geolocation.getCurrentPosition(callback, error, {
      enableHighAccuracy: false // network-based, ~1-3km accuracy
    });

    On mobile, both Android and iOS now support approximate location permissions. Use them. If your weather app is requesting precise location, you're part of the problem.

    For Android, request ACCESS_COARSE_LOCATION instead of ACCESS_FINE_LOCATION. On iOS, you'll get the accuracy reduction dialog automatically in newer versions, but you should design your app to work with reduced accuracy from the start.

    Step 2: Truncate Coordinates Before They Leave the Device

    Even if you collect precise coordinates for a legitimate reason (navigation, mapping), you should truncate or round them before storing or transmitting when full precision isn't needed.

    python
    import math
    
    def reduce_location_precision(lat, lon, precision_km=1.0):
        """
        Snap coordinates to a grid to reduce precision.
        ~1km grid uses 2 decimal places for lat/lon.
        """
        # Each 0.01 degree of latitude is roughly 1.11 km
        decimal_places = max(0, round(math.log10(111.0 / precision_km)))
        
        return (
            round(lat, decimal_places),
            round(lon, decimal_places)
        )
    
    # Full precision: user is on a specific aircraft carrier deck
    print(reduce_location_precision(43.096181, 5.879964, precision_km=0.01))
    # (43.0962, 5.88)
    
    # Reduced to ~1km: user is in the general Toulon harbor area
    print(reduce_location_precision(43.096181, 5.879964, precision_km=1.0))
    # (43.1, 5.9)
    
    # City-level: user is near Toulon
    print(reduce_location_precision(43.096181, 5.879964, precision_km=10.0))
    # (43.1, 5.9) -> at this scale, many users collapse to same point

    The key insight: do this server-side, not just client-side. A motivated attacker can bypass any client-side truncation. Your API should enforce precision limits based on what the feature actually requires.

    Step 3: Implement Server-Side Privacy Zones

    The fitness app in the news lets users set privacy zones around their home address. Cool feature. Problem is, it's opt-in and only enforced visually on the client. Researchers have repeatedly shown these can be reverse-engineered.

    If you're building anything that displays user-generated location data, enforce exclusion zones at the API level:

    python
    from shapely.geometry import Point, Polygon
    
    def filter_sensitive_locations(activity_points, exclusion_zones):
        """
        Remove or fuzz any GPS points that fall within exclusion zones.
        This runs SERVER-SIDE before any data hits a public endpoint.
        """
        filtered = []
        for point in activity_points:
            location = Point(point['lon'], point['lat'])
            in_zone = any(
                zone['polygon'].contains(location)
                for zone in exclusion_zones
            )
            if in_zone:
                # Option A: skip the point entirely
                continue
                # Option B: add noise (comment out the continue above)
                # point = add_differential_noise(point, epsilon=0.5)
            filtered.append(point)
        return filtered

    The important thing: this isn't just about user-defined zones. You should maintain a list of known sensitive areas (military installations, domestic violence shelters, government buildings) and apply filtering automatically.

    Step 4: Defend Against Aggregation Attacks

    This is the sneaky one. Even if individual data points are fuzzy, collecting enough of them over time can reveal precise patterns. That's exactly how Le Monde tracked the carrier — individual workouts were somewhat vague, but tracking multiple sailors over days painted a clear picture.

    The defense here is differential privacy. The idea is to add calibrated statistical noise so that aggregate queries don't reveal individual data points:

    python
    import numpy as np
    
    def add_differential_noise(lat, lon, epsilon=1.0):
        """
        Add Laplacian noise to coordinates.
        Lower epsilon = more privacy, less accuracy.
        epsilon=1.0 is a common starting point.
        """
        # Scale noise to roughly 100m at epsilon=1.0
        sensitivity = 0.001  # ~111 meters in latitude
        scale = sensitivity / epsilon
        
        noisy_lat = lat + np.random.laplace(0, scale)
        noisy_lon = lon + np.random.laplace(0, scale)
        
        return noisy_lat, noisy_lon

    But here's what I've learned after implementing this in a couple of projects: differential privacy is hard to get right. The math is unforgiving, and it's easy to set parameters that either destroy your data's usefulness or provide almost no actual privacy. If you're serious about this, look into established libraries like Google's differential privacy library or OpenDP rather than rolling your own.

    Step 5: Make Privacy the Default, Not a Setting

    This is the non-code part, and honestly it's the most important.

    The aircraft carrier wasn't found because the app lacked privacy features. It had them. The problem was that the default was public, and most users never changed it.

    When you're designing your data model and API, ask yourself:

    • Is location data public by default? Change it to private.
    • Can users discover other users by location without explicit opt-in? Remove that or gate it behind intentional consent.
    • Are you retaining precise location history longer than you need to? Set aggressive TTLs.
    • Does your public API return more location precision than the UI displays? Truncate at the API layer.

    Prevention Checklist

    Before your next deploy, audit your location handling:

    • Request minimum required precision from the OS
    • Truncate coordinates server-side before storage
    • Default all location-sharing features to off
    • Implement server-side exclusion zones (not just client-side)
    • Add noise to any publicly queryable location data
    • Set retention policies — delete precise coordinates after deriving what you need
    • Rate-limit location-based queries to prevent scraping
    • Log and alert on bulk location data access

    I've been building web apps for over eight years, and location data is one of those things that seems simple until it goes sideways. A latitude and longitude pair looks innocuous in a database column. But multiply it by thousands of users and weeks of history, and you've got a surveillance tool sitting in your PostgreSQL instance.

    The fix isn't complicated. It's just not the default anywhere yet. Make it the default in your app.

    How to Stop Your App from Leaking User Locations (Yes, It Matters) | Authon Blog