Record Verification - Exploring verifiable ENS records

Hey everyone,

I’m Vedant (envoy1084.eth), I work at Namespace, where I like experimenting with ENS-related ideas.

Lately I’ve been working on an idea called Record Verification. I presented it during the ENS x AI call, where I learned that jkm.eth and Lighthouse Labs have also been working on the same problem and have a PoC live at atst.me
I thought other people might also be working on related projects, so I wanted to outline my ideas here to get feedback from the community.

Where the idea came from

The idea started with a small interaction in VS Code.

I was installing the Apollo GraphQL extension when VS Code showed me a trust prompt. One line stood out:

Apollo GraphQL has verified ownership of www.apollographql.com.

That message does not guarantee that the extension is safe. It does not audit the code or promise that the publisher will never do anything malicious. But it does establish one useful fact: the extension publisher has proved a connection to the Apollo domain.

That small piece of evidence makes impersonation harder and gives the user more context before clicking “Trust Publisher & Install.”

It made me think about ENS.

ENS names can already publish websites, social accounts, payment addresses, content, application endpoints, and many other records:

text("url")        = "https://example.com"
text("com.github") = "alice"
addr(60)           = 0x3e708BBb834B769b1ef098946ed1FFdC17450d98
contenthash()      = ipfs://bafy...

But what does one of these records actually prove?

The gap in ENS records today

An ENS resolver tells us what value has been set for a name. If url record for alice.eth returns https://example.com, we know that the record currently points there.

What we do not know is whether the controller of example.com has accepted that connection.

The same is true for other records:

  • A name can publish someone else’s GitHub username.
  • A name can copy someone else’s Bitcoin or Ethereum address.
  • A name can point to a content identifier it did not publish.

This is not a flaw in ENS. Resolver records are intentionally flexible. They are statements made through the resolver, and in many cases that is exactly what we need.

A profile description, location, or header image does not necessarily need external verification. But some records are used for payments, account linking, agent discovery, application connections, and other actions where a stronger signal would be useful.

The question is:

Can we give applications an optional, standard way to verify the connection
between one ENS record and the external resource it points to?

That is the problem Record Verification is trying to solve.

The idea in one sentence

The current ENS authority approves one exact resolver record, and the external target provides its own proof for that same record.

Both sides are connected through a common claim. A client or SDK verifies the claim against live ENS state and method-specific evidence from the target.

There is no permanent onchain “verified” flag, and no new verification contract is required. Verification happens in wallets, apps, SDKs, indexers, or other clients that choose to use it.

How a record opts in

Verification is optional and configured one record at a time.

Suppose alice.eth has this URL record:

text("url") = "https://example.com/profile"

To opt that particular record into verification, the name also publishes a
companion text record:

text("verification[text][url]") = "ensrv1 a=1 m=https-origin.v1"

This small value is called a verification descriptor. It tells a verifier:

  • ensrv1: which version of the common Record Verification protocol to use;
  • a=1: how to determine the current authority for this ENS name; and
  • m=https-origin.v1: how the external target will prove control.

The descriptor does not contain the proof itself. It only tells the verifier which rules apply and, for methods that need it, where the proof can be found.

A walkthrough: verifying a URL record

Let’s follow the URL example from start to finish.

1. Alice publishes the URL

alice.eth → text("url") → https://example.com/profile

At this point, ENS only tells us that the resolver returns this URL. It does not yet prove that example.com accepts the association.

2. Alice enables verification for that record

text("verification[text][url]") = "ensrv1 a=1 m=https-origin.v1"

This selects the HTTPS-origin verification method.

3. The verifier determines the current ENS authority

“Authority” means the account that is allowed to approve verification for the exact ENS name.

The verifier calculates it from ENS state:

  • For a normal unwrapped .eth name, this is the Base Registrar registrant.
  • For a wrapped name, it is generally the exact Name Wrapper owner.
  • Other exact ENS names use the Registry owner when the current authority profile supports them.

This distinction matters because the account allowed to update a resolver record is not always the owner of the name.

4. The authority signs one record-bound claim

The authority signs a claim containing the important parts of the relationship:

ENS name          alice.eth
record            text("url")
record value      https://example.com/profile
current authority 0x1234...
method            https-origin.v1
target            https://example.com
issued at         ...
valid until       ...

The complete record value is included through a cryptographic hash. Changing the URL, record key, ENS name, authority, method, target, or expiry changes the signed claim.

This is important: the signature is not a general statement that “Alice owns example.com.” It approves one exact relationship for one exact live ENS record.

5. The website publishes the proof

For https-origin.v1, the verifier derives a deterministic proof location on
the URL’s origin:

https://example.com/.well-known/ens-record-verification/<proof-key>

The controller of example.com publishes the authority-signed proof at that location.

6. A client verifies everything against live state

The verifier then:

  1. reads the URL record and verification descriptor from the same ENS snapshot
  2. calculates the current authority for alice.eth
  3. derives the current record hash, HTTPS origin, and proof location
  4. fetches the proof from example.com
  5. checks that every claim field matches the live ENS record
  6. validates the authority signature; and
  7. checks the claim expiry and method freshness rules.

If every required check succeeds, the client can return:

{
  "verified": true,
  "verificationType": "control"
}

In plain language, that means:

The current authority for alice.eth approved this exact URL record, and the
controller of https://example.com published that approval at the required
location.

If the URL changes, the authority changes, the descriptor changes, the proof is removed, or the claim expires, a fresh verification will no longer pass.

The original URL record is still returned either way. Verification is an additional signal, not a replacement for ENS resolution.

What “verified” does and does not mean

The word “verified” can easily become broader than the evidence behind it, so the proposal intentionally gives it a narrow meaning.

For the URL example, it proves control of the HTTPS-origin publication capability for this exact ENS record.

It does not prove that:

  • the website is safe
  • its content is accurate
  • the ENS name and domain have the same legal owner
  • the target is free from phishing or malicious behavior, or
  • ENS endorses either party.

Other verification methods

The current draft explores three method families:

Method What the target does Status
https-origin.v1 Publishes the proof at a deterministic HTTPS well-known path. Concrete draft
dns-txt.v1 Publishes the complete proof in a DNSSEC-authenticated TXT record. Concrete draft
account-signature.<profile>.v1 The account in an ENS address record signs evidence bound to the common claim. Candidate profiles

The same structure could later support social accounts, content-addressed resources, issuer attestations, or future resolver record types. Those methods should only be added when they can make a precise and testable claim.


Feedback

We have started to collaborate with Lighthouse on a more complete standard, and I would like feedback on my ideas above to help shape those conversations. I’d love to hear what you think:

  • Has anyone attempted record-level verification before?
  • Does this approach make sense?
  • Is there anything missing?

The detailed protocol components, examples, method drafts, and open decisions are available here:

Read the Record Verification documentation

For faster discussion, you can also join the Record Verification Telegram group.

5 Likes

When designing our attestation proofs, we thought it was important to keep the records small enough to fit into the same number of storage slots that would be needed to store a single IPFS URI. We accomplished that by offloading much of the signature details to things that could be inferred, instead of including them in the payload itself; for example, by putting the name of the attester in the key name instead of the value, users can provide proofs from multiple authorities and consumers can easily check for proofs from signers they specifically trust. It also means the signer doesn’t need to be included in the payload itself, greatly shrinking the size.

In many off-chain realms, size is not a large constraint so the convention seems to be to include a lot of extra details to make sure consumers always have easy access to all the details they need for verification. But with blockchain engineering, conciseness is a constant goal, and I think it makes sense to keep things compact when stored as a record.

We chose CBOR for encoding the proof, which helps keep things compact and portable. It also makes the final proof deterministic, which has many benefits. Famously, bitcoin’s transaction malleability issue meant that a single transaction could have multiple valid transaction hashes, making it hard to track specific transactions that have been issued. Mt. Gox didn’t foresee that issue, and ended up losing so much money they collapsed.

I fear that using human-centric ASCII text and white space delimiters would not scale efficiently and would introduce too much variability for a system that relies on cryptographic proofs. Of course, I also am of the opinion that ENS text records should be considered on-chain data and therefore we shouldn’t expect them to be read directly by users, but instead interpreted by middleware which then displays the data in a user-friendly way.

1 Like