Image privacy research

How a GPS Location Is Actually Stored in a Photo

Searching an image file for the text GPS usually finds nothing, even when the file definitely contains a location. The reason is that GPS data is not stored as text. It lives in a nested EXIF tag directory, addressed by numeric tag identifiers. We parse that directory in our own fixture, so the explanation rests on the actual bytes rather than on a description of the standard.

What this guide helps you decide

A photo can carry the location where it was taken. Where does that location physically live in the file, and why does searching for the word GPS not find it?

This research describes the EXIF tag structure that holds GPS data, using this repository's own generated fixture. It does not provide location data, does not describe a real place, and does not claim any specific camera writes these tags.

Try it on the anchor product: BeanNest Tools /image/.

Where EXIF lives in a JPEG

EXIF is carried in an APP1 segment. Inside that segment is an Exif header, then a TIFF block with its own byte-order header and an offset to the first image file directory. Our fixture writes that structure directly, which makes each field inspectable.

How our parser locates the tags

The analyzer finds the APP1 marker, skips the segment length and the Exif header, reads the TIFF start, follows the offset to the first directory, then reads the entry count and walks each twelve-byte entry reading its tag identifier. It reports the tag numbers it found rather than a rendered value.

The two tags that matter here

Our fixture declares tag 0x010F, which is the camera Make field, and tag 0x8825, which is the GPS information directory pointer. The pointer is what says a location block exists. Our analyzer reports hasGpsIfd as true for that file and false for the equivalent file built without EXIF.

Why text search fails

The tag identifier 0x8825 is two bytes, not the characters G, P, and S. A location is stored as rational numbers in a separate directory, again as binary. Text search therefore cannot find the location, even though the location is present. This is why a metadata claim based on a search result is unreliable.

What the fixture deliberately contains

The fixture writes a placeholder latitude reference and placeholder rational values so the directory structure is exercisable. The committed file contains no real coordinates and describes no actual place. The evidence is the structure, and the structure is what the guides cite.

The privacy consequence

Because location is structural and not textual, removing it requires removing or rewriting the tag directory, not editing visible file content. A tool that reports it stripped metadata should therefore be checked against the tag directory, which is exactly the check our analyzer performs.

Reading a twelve-byte IFD entry

Each entry in an image file directory is twelve bytes: a two-byte tag identifier, a two-byte type code, a four-byte count, and four bytes holding either the value itself or an offset to it depending on size. Our parser reads all four fields in order and reports the tag identifier. For the make field the value is a twelve-byte string that does not fit inline, so the fourth field holds an offset to the string. For the GPS pointer the value is a single four-byte offset, which is why the fourth field holds it directly.

Why the GPS block is a separate directory

The GPS tag does not carry coordinates. It carries the offset of a second directory that holds them, so location data is two levels deep: the first directory names the block, and the second contains the values. That nesting is why a shallow parser can report EXIF present while missing the location entirely, and why our analyzer reports both the presence of the pointer tag and the count of entries it found.

Rational values and why they are hard to edit

Latitude and longitude are stored as three rational numbers each, degrees, minutes, and seconds, with a separate reference letter for hemisphere. A rational is two four-byte integers, a numerator and a denominator, which is twenty-four bytes per coordinate. Editing a location therefore means rewriting binary fields at known offsets, not replacing text. A tool that claims to remove location must remove or rewrite that directory, and a structural check is how you confirm it did.

How the fixture stays safe

The committed fixture writes placeholder numerators and denominators and a placeholder hemisphere letter so the directory is structurally valid and parseable. No real coordinate exists in the file and none is derived from any real place. The evidence is the tag structure, and the guides cite the structure rather than any value, which is why the fixture can be published without any privacy cost.

Why the pointer tag is the finding

Reporting that EXIF is present says a metadata block exists. Reporting that tag 0x8825 is present says that a location block exists inside it. The second statement is the one that matters for privacy, and it is the one a shallow check would miss. Our analyzer parses the directory and reports the tag identifiers it found, so the presence of the pointer is a measured fact rather than an inference from the segment name.

How the two directories relate

The first directory holds the camera fields and the pointer. The pointer holds an offset to a second directory, which holds the coordinate values. The second directory is not referenced by the segment name, only by that numeric offset, which is why a parser must follow the pointer rather than search for a label. Following it is what our analyzer does, and the fixture is built so the pointer leads to a real, parseable directory.

Why the fixture uses placeholder values

Writing a real coordinate would embed a real place in a published file for no benefit, since the evidence is the structure rather than the value. The fixture therefore writes placeholder numerators, denominators, and a hemisphere letter, which produce a valid directory that the parser can traverse. The guides cite the tag structure and never a coordinate, which is why the file can be committed without any privacy cost.

What a removal tool must do

Because location is a nested binary directory, removing it means removing or rewriting that directory and updating the pointer, not editing visible content. A tool that only strips the EXIF segment entirely would also remove the camera fields, which is a legitimate choice, while a tool that claims to remove location alone must operate on the nested directory. Either way, verifying the result means re-parsing the tag list and confirming the pointer is gone.

How this generalises beyond GPS

The same nested-directory pattern holds for other EXIF structures, including the interoperability directory and maker notes. A parser that follows pointers is therefore useful beyond location, and a check that only looks at the first directory will miss all of them. The guide describes the mechanism through GPS because that is the case with the clearest privacy consequence and the one exercised by the committed fixture.

How the tag list is produced

The parser locates the APP1 segment, skips the segment length and the six-byte Exif header, reads the TIFF start, follows the offset in the TIFF header to the first directory, reads the entry count, then reads each twelve-byte entry's tag identifier. The result is a list of numeric tags rather than rendered values. Reporting numbers rather than values is deliberate: the numbers are what the file contains, and the values would require additional type handling the corpus does not need.

Why the make tag appears alongside the pointer

The fixture declares two tags in its first directory: the camera make field and the GPS pointer. Including a familiar tag beside the pointer demonstrates that the parser reports all entries rather than special-casing location, and it gives the reader a tag they can recognise as a cross-check. A parser that only reported the pointer would produce a suspiciously narrow result on a file that contains more.

What a removal verification should check

After a claimed location removal, re-running the parser should show that the pointer tag is absent from the list. That is a direct check on the structure rather than on a tool's report of what it did, and it works regardless of which tool performed the removal. The guide recommends this check because a tool that removed the segment entirely and one that rewrote the directory both produce a verifiable result.

How the fixture relates to real camera files

The fixture writes the same structural layout a camera would write: an Exif header, a TIFF block, a first directory with a make field and a pointer, and a second directory with coordinate rationals. It does not reproduce the full set of tags a camera adds, because the evidence needed is the pointer and its target rather than a complete metadata profile. The guides are explicit that the fixture is a structural demonstration rather than a sample of a real file.

First-party evidence and provenance

How we checked this

We wrote four small images with this repository's own generator, then parsed each file's container segments and EXIF tag directory with this repository's own analyzer. Both are dependency-free and deterministic, so the same commands reproduce the same byte counts. For this guide we parsed the EXIF tag directory inside our generated JPEG and reported the numeric tag identifiers found, which is what shows that location is structural rather than textual.

Method
We wrote four small images with this repository's own generator, then parsed each file's container segments and EXIF tag directory with this repository's own analyzer. Both are dependency-free and deterministic, so the same commands reproduce the same byte counts.
Environment
Node.js on a desktop workstation. The images are generated from code in this repository; no camera photo, third-party file, or network resource was used.
Captured
Reviewed by
BeanNest Studio

Repository evidence artifacts:

  • tools/research-evidence/image/analysis-2026-09-20.json
  • tools/research-evidence/image/README.md