{
  "id": "DPE-2026-0021",
  "name": "Probing the visitor's own device",
  "slug": "probing-the-visitors-own-device",
  "name_nl": "De pagina tast je eigen apparaat af",
  "family": "data",
  "applies_to": [
    "web",
    "desktop"
  ],
  "summary": "A page reaches into the visitor's own machine or local network to see what is installed there.",
  "not_a_vulnerability": "Nothing is broken into. The probe uses ordinary requests that any page may make, and the software it looks for answers as designed. The objection is that the page is looking at all.",
  "mechanism": {
    "what": "While the page is open, requests go to the loopback address or to addresses on the visitor's own network, on a fixed set of ports and paths. What answers, how fast it answers, and whether it answers at all tells the sender which software is installed or which devices are present. The result is a characteristic of the machine that no interface exposes and the visitor never offered.",
    "why_it_matters": "This is not the page describing itself, it is the page describing the visitor's equipment. The properties found are stable, they say something about the person, and the visitor has no way to see it happen: nothing appears on screen, and blocking it requires knowing it is there.",
    "common_causes": [
      "a fraud or device-recognition component checking for locally installed software",
      "a payment or checkout integration probing for a local helper application",
      "a component that enumerates the local network to recognise a returning environment"
    ],
    "not_this": "Reading properties the browser exposes about itself, such as fonts or a canvas rendering, is Device fingerprinting. What distinguishes this entry is that the traffic leaves the page and addresses the visitor's own machine or network, which the browser does not present as a property at all."
  },
  "detection": {
    "indicator": "Requests from the page to a loopback address or to addresses in the visitor's own network range, on a fixed set of ports or paths, present in the capture. Where they occur in every consent mode, that is part of the same observation.",
    "method": "network-observed",
    "qod": 92,
    "capture_requirements": [
      "clean profile, and a capture that records requests which never leave the machine; many tools filter loopback traffic by default",
      "capture per consent mode, since the finding is stronger where the probe runs after refusal as well",
      "record the port set and the paths, because that is what makes the purpose identifiable",
      "check the page's own content security policy: a policy that permits the loopback range is corroboration from the site's own configuration"
    ],
    "attribution": [
      "cdp-initiator",
      "har-pageref"
    ]
  },
  "falsifiers": [
    {
      "condition": "The probe is part of a function the visitor started, such as a local card reader or signing application they chose to use.",
      "checkable": "manual",
      "if_true": "drop"
    },
    {
      "condition": "The traffic is generated by an extension or by software the visitor installed, not by the page.",
      "checkable": "automated",
      "if_true": "drop",
      "note": "Attribute through the initiator chain, and repeat in a clean profile with no extensions."
    },
    {
      "condition": "The probe only runs after an explicit action by the visitor.",
      "checkable": "automated",
      "if_true": "weaken"
    },
    {
      "condition": "Every probe fails and nothing about the result is transmitted onward.",
      "checkable": "manual",
      "if_true": "weaken",
      "note": "Under the terminal-equipment provision the reading itself is the act, so this weakens rather than removes the finding."
    }
  ],
  "legal": {
    "provisions": [
      "nl-tw-11-7a",
      "eu-gdpr-6-1-a",
      "eu-gdpr-5-1-c"
    ],
    "rebuttals": [
      {
        "objection": "It is for fraud prevention.",
        "answer": "That is a purpose, and it has to be stated, limited and justified against a scan of the visitor's own machine. It is not a reason the visitor cannot be told."
      },
      {
        "objection": "We only check whether a helper application is running.",
        "answer": "Then say so, at the moment it happens, and stop when the visitor refuses. Whether the check is narrow is measurable from the port set in the capture."
      },
      {
        "objection": "No personal data is collected.",
        "answer": "The provision on terminal equipment attaches to reading from the device, whether or not the result is personal data. And what software someone runs is a characteristic of that person."
      }
    ]
  },
  "related": [
    "DPE-2026-0007",
    "DPE-2026-0002"
  ],
  "seen_in_the_wild": {
    "confirmed": false,
    "note": "Observed in practice by the authors but not yet backed by a published reference. Set to false until a citation exists: a claim without a source is exactly what this catalogue holds others to."
  },
  "in_practice": {
    "dpia": "Verify whether any component addresses the visitor's own machine or network, and in which consent states it does so.",
    "procurement": "No page issues requests to the visitor's loopback address or local network, demonstrated by a capture that includes loopback traffic.",
    "complaint": "A capture including loopback requests, the port and path set, the consent state per capture, and the content security policy of the page.",
    "audit_question": "Does anything on this page talk to the visitor's own computer, and on which ports?",
    "audit_question_nl": "Praat er iets op deze pagina met de computer van de bezoeker zelf, en op welke poorten?",
    "complaint_nl": "Een opname of uitdraai die laat zien wat er werkelijk gebeurt, met de datum erbij en het land van waaruit is gemeten.",
    "objection_nl": "Dat is een beveiligingscontrole.",
    "answer_nl": "Vraag welke poorten en welke software er wordt gezocht, en wat er met die uitkomst gebeurt."
  },
  "schema_version": "2.0",
  "status": "active",
  "credit": [
    {
      "name": "Mick Beer",
      "role": "proposed",
      "date": "2026-07-26"
    }
  ],
  "does_not_establish": [
    "harm; the catalogue standardises a finding so it can be referred to, it does not weigh it",
    "severity; there is no score here, by design. Weighing belongs to whoever applies the entry to a concrete case",
    "unlawfulness; that is for a supervisory authority or a court",
    "intent; a fault is usually a build decision, not a plan",
    "absence: not finding it in one capture is not evidence that it is not there"
  ],
  "reproduction": {
    "methods": [
      {
        "tier": "manual",
        "path": "METHOD.md",
        "expect": "no dedicated reproduction exists yet; follow the general method and the indicator above"
      }
    ]
  },
  "changes": [
    {
      "at": "2026-07-26T00:00:00Z",
      "actor": "registry",
      "entries": [
        "Entry created.",
        "Name assigned.",
        "Detection method and falsifiers defined.",
        "Legal provisions linked."
      ]
    }
  ],
  "summary_nl": "Een pagina tast de eigen machine of het thuisnetwerk van de bezoeker af om te zien wat daar draait."
}
