The Heatmap That Mapped the Base — JavaScript Bug Hunt

Modelled on the Strava global heatmap (January 2018): aggregated, "anonymised" activity data was published worldwide.

  • Language: JavaScript
  • Layer: Backend
  • Difficulty: Hard
  • Concepts: Privacy, Aggregation
  • Modelled on: Strava · 2018
  • Visible tests: a busy cell is published; a single-contributor cell is withheld
  • Reward: 50 XP for a complete fix

Briefing

Modelled on the Strava global heatmap (January 2018): aggregated, "anonymised" activity data was published worldwide. In remote regions the only people running were soldiers, so the heatmap traced the perimeters and patrol routes of undisclosed military bases.

heatmap.js publishes every cell that has any activity at all.

Fix buildHeatmap so a cell is only published when enough distinct users contributed to it.

Bug report

BUG-STRAVA · Priority: Critical (privacy) · Reported by: trust & safety

buildHeatmap(activities, minUsers) must return the published cells as a sorted array of { cell, count } where:

  • count is the number of DISTINCT users with activity in that cell
  • only cells with count >= minUsers are published
  • cells are sorted by cell name ascending

Observed: every cell is published, including cells whose entire signal comes from a single person.

Logs

[heatmap] published cell "af-77-12" contributors=1
[heatmap] cell outlines a facility that is not on any map

The code as shipped

src/geo/heatmap.js (editable)

// Aggregates activities into publishable heatmap cells.
exports.buildHeatmap = function (activities, minUsers) {
  var byCell = {};
  for (var i = 0; i < activities.length; i++) {
    var a = activities[i];
    if (!byCell[a.cell]) byCell[a.cell] = {};
    byCell[a.cell][a.userId] = true;
  }
  var out = [];
  var cells = Object.keys(byCell);
  for (var c = 0; c < cells.length; c++) {
    out.push({ cell: cells[c], count: Object.keys(byCell[cells[c]]).length });
  }
  out.sort(function (x, y) { return x.cell < y.cell ? -1 : (x.cell > y.cell ? 1 : 0); });
  return out;
};

Read-only context: src/geo/PRIVACY.js.

Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More JavaScript bug hunts.