Regex anchors, and three commits to validate one IDFA
A 2016 validation bug that took three commits: why regex anchors matter, and why an IDFA is a UUID, not a 40-character UDID.
From 2016 · 2 min read · Published September 4, 2026
In early 2016 I was working on an analytics product that let customers exclude their own traffic from their metrics: internal IP addresses, test accounts, and, as mobile grew, specific devices. My task was to add device exclusions by advertising identifier, which meant validating the IDFA format with a regex.
The feature itself was straightforward. A new exclusion subclass, a new type in the list, and a validation to reject values that weren't well-formed identifiers. The validation took three commits to get right, and I'm still not sure the last one was.
Take one
The first version of the check looked like this (illustrative, but faithful to the shape):
def validates_value
errors.add(:value, "is not a valid IDFA") unless /^[a-f]|[a-f]+\d/.match(value)
endThat alternation means "starts with a hex letter, or contains a hex letter followed by a digit, anywhere." Almost any string with a letter in it passes.
Take two
A day later, a "strengthening" commit:
/[a-f0-9]{40}/Better: forty hex characters. But it's unanchored, so it matches forty hex characters anywhere in the string. Garbage, then a valid-looking run, then more garbage, passes.
Take three
Then the version that shipped:
/^([a-fA-F0-9]{40})$/Anchored at both ends, case-insensitive hex, exactly forty characters. Finally, a regex that says what it means.
The two lessons: regex anchors and real formats
1. Anchor your patterns. An unanchored regex used for validation is almost always a bug. It answers "does this string contain something valid?" when you meant "is this string valid?" (In Ruby specifically, \A and \z are safer than ^ and $, which match at line boundaries, so a value with a newline can still sneak through.)
2. Know the format before you write the check. A forty-character hex string is the shape of the old iOS device identifier, the UDID, which Apple had already deprecated for advertising use. The advertising identifier, the IDFA, is a standard UUID: 32 hex characters in an 8-4-4-4-12 pattern with hyphens. So the final regex was well-formed and still validated the wrong thing.
I only noticed that years later, rereading the code for this post. At the time, three commits in, it felt done.
Related: Facebook Pixel firing twice: one pixel, one init · Wrapping a native SDK in a React Native native module