Credential Revocation: Status Lists, Herd Privacy, and the Correlation Problem

Aug 28, 2026

Introduction

An earlier post showed how to issue Verifiable Credentials against Bitcoin-anchored DIDs. Issuance is the part that looks good in a demonstration. In production, a different part decides if a credential system is usable: what happens when a credential must become invalid. Examples:

  • An employee leaves.
  • An authority suspends a license.
  • A certification expires.
  • An issuer finds that it issued a credential in error.

Many identity architectures are well designed in other areas but fail at revocation. Usually, the cause is that the revocation mechanism adds back the centralization and correlation that the rest of the system avoids. This post examines the status list mechanisms that are in use, their privacy properties, and the alternatives.

What Revocation Is Not

Two misconceptions are common. This section corrects them first.

Deactivation of the issuer's DID does not revoke its credentials. The post about deactivation explained the durability half. If a key that was valid at the time signed a credential, the credential can still verify after deactivation. This is true only if two conditions are true:

  1. The verifier resolves the issuer's DID at that historical version.
  2. The verifier can independently find the time of the signature.

DID Core gives both as necessary conditions. The second condition is easy to forget. The verifier needs a trusted time for the signature, for example from a separate anchor, a timestamp service, or out-of-band evidence. Without this time, historical resolution is not a durability property. Instead, it lets any person who holds the retired key backdate signatures.

If the two conditions are true, the behavior is intentional. It lets a credential stay valid after the organization that issued it stops operation. If you want a credential to fail verification, deactivation is not the correct mechanism.

Rotation of the signing key also does not revoke credentials. The reason and the conditions are the same. With historical resolution, old signatures continue to verify. Some verifiers treat a key rotation as a revocation of all items that the old key signed. Such a verifier makes each rotation a mass revocation event. This fallback is defensible if the verifier cannot find the time of each signature, but in other cases it revokes many valid credentials.

DID Core makes a stronger statement about this fallback. It examines the case where a verifier cannot reliably find the state of a DID at the time of the signature. For this case, DID Core gives this rule: "the only safe course is to disallow any consideration of DID state with respect to time, except the present moment."

Revocation is a separate mechanism. You must design it into the system from the start. If a credential has no status information, the issuer cannot revoke it later. No change to the issuer's DID can change this.

Bitstring Status List

The correct status mechanism for you depends on your credential format. For W3C Verifiable Credentials, the mechanism is Bitstring Status List. It came from the earlier StatusList2021 work, and it became a W3C Recommendation in May 2025. For credentials that use JOSE or COSE (for example SD-JWT VC and ISO mdoc), the mechanism is IETF Token Status List. As of August 2026, this draft is in the RFC Editor queue, with an intended status of Proposed Standard.

Both mechanisms use the same core construction: a compressed bitstring that the verifier fetches as a whole, with a size that gives herd privacy. The differences are in how each mechanism encodes the list and in how a credential refers to its entry. This post examines the W3C version. The privacy analysis applies to the IETF version with almost no changes.

The construction is simple and clever. The issuer keeps a large bitstring. Each position in the bitstring corresponds to one issued credential. A bit with the value 1 means "revoked", and 0 means "not revoked". Then the Bitstring Generation Algorithm says: "Generate a compressed bitstring by using the GZIP compression algorithm on the bitstring and then Multibase-encode the result using base64url (with no padding)." The issuer publishes the result inside a separate Verifiable Credential and signs that credential.

Each issued credential has a credentialStatus entry. The entry points to the list and gives the index of the credential:

{
  "credentialStatus": {
    "id": "https://issuer.example/status/3#94567",
    "type": "BitstringStatusListEntry",
    "statusPurpose": "revocation",
    "statusListIndex": "94567",
    "statusListCredential": "https://issuer.example/status/3"
  }
}

To check the status, a verifier does these steps:

  1. Fetch the status list credential.
  2. Verify the issuer's signature on it.
  3. Decompress the bitstring.
  4. Read bit 94567.

Two properties let this mechanism work at scale:

  • Compression does most of the work. A bitstring that is almost all zeros compresses very well. The spec says that a list of 131,072 entries is 16 KB before compression. If the issuer revokes only a small number of credentials, GZIP compresses that list to a few hundred bytes.
  • The check is one fetch and one bit lookup. The verifier does not send a request to the issuer for each credential.

The specification defines four statusPurpose values, not one: revocation, suspension, refresh, and message. Suspension is reversible and very useful, and frequently it is what an organization actually means. A license that is under review is not the same as a license that the authority permanently withdrew. If you merge the two states, you lose information that the verifier can require. The message value carries an arbitrary message about the status, and refresh tells the verifier that an updated credential is available.

Herd Privacy and Why the List Is Big

The Validate Algorithm sets a minimum size of 131,072 entries, "unless a different lower bound is established by a specific ecosystem specification". The number is not arbitrary, and its purpose is not efficiency. It is a privacy parameter, and the spec says so: "This size ensures an adequate amount of group privacy in the average case. If better group privacy is required, the bitstring can be made larger."

The reason is as follows. When a verifier fetches a status list, the issuer's server learns that someone checks some credential on that list. The server does not learn which credential, because the verifier downloads the full list and does the lookup locally. Thus, the list hides the holder among all the holders on the same list. This is herd privacy. The size of the herd is the number of credentials on the list, as the spec explains in Revocation Bitstring Length.

Thus, if a list has few credentials, the protection is weak. Some issuers make a separate status list for each credential. Each fetch of such a list identifies the credential exactly, so the issuer gets a report each time a verifier checks that credential. If an issuer puts 40 customers on a list, each customer has an anonymity set of 1 in 40.

The minimum size does not stop this. The minimum applies to the length of the bitstring, not to the number of credentials that have a position in it. Thus, a list for one credential passes the Validate Algorithm with no error if the issuer pads the list to 131,072 bits. That algorithm has only one length check. It raises an error if the expanded bitstring length, divided by the status size, is less than the minimum. A list that is almost empty passes that check.

The spec identifies this construction as an attack that a malicious issuer can do. The spec says that holder software which serves many holders can detect the attack, for example with an opt-in process. The checks that the verifier does cannot detect it.

This causes a real operational conflict. Issuers usually want to divide status lists by credential type, by customer, by issuance batch, or by region. Each of these divisions makes the herd smaller. For privacy, the better choice is a small number of large lists. This choice is the opposite of what many data modelers do by instinct.

What the Issuer Still Learns

Herd privacy hides which credential the verifier checks. It does not hide that a check occurred.

The issuer's server sees each request: an IP address, a timestamp, a TLS fingerprint, and possibly a user agent. Over time, this data becomes a meaningful signal. An issuer of professional licenses can see which employers do checks, and about when they start to hire more staff. An issuer of age credentials can see which services verify credentials, and how many. This data does not identify the holder directly. But it is real information about the verifier, and verifiers can have high expectations of confidentiality.

A second problem is less obvious and more serious. If the verifier fetches the status list at the time a holder presents a credential, the time of that fetch correlates with the presentation. Some issuers can also see the presentation side, or they collude with a party that can see it. Such an issuer learns much more than the herd size suggests.

Mitigations exist. Most of them break the link between the presentation and the fetch, or keep the fetch off the issuer's infrastructure:

Cache aggressively. A verifier can fetch each status list on a schedule and do lookups from its cache. Then the fetch has no relation to a specific presentation, and the spec's section on verifier caching describes this privacy gain. The cost is stale data, and stale data is exactly the problem that revocation must solve. Thus, the cache interval is a policy decision: a longer interval gives more resistance to correlation but a longer revocation delay. Set the interval explicitly, and do not let an HTTP library choose it.

Serve the list from a CDN or mirror that the issuer does not operate. The issuer signs the status list credential. Thus, its authenticity does not depend on the location that the verifier fetches it from, and any mirror can serve it. If the issuer does not operate the mirror, the request does not go to the issuer's own infrastructure. The issuer makes this deployment choice, not the verifier, because the Validate Algorithm tells the verifier to dereference the statusListCredential URL in the credential. This choice is simple, and the spec says that a content distribution network can increase the privacy of holders.

Fetch all the lists. A verifier can fetch all the status lists of an issuer on a schedule, not only the lists that it needs. Then its fetch pattern tells the issuer nothing. This method is practical if the lists are small, and compression usually makes them small.

The Correlation Problem with Selective Disclosure

The next interaction weakens much privacy work. It is also the reason for this post.

An earlier post described selective disclosure. With it, you can prove that you are over 18 and not show your birth date. You can also prove your employment and not show your salary. The purpose is to decrease what a verifier learns. It is also important not to give every verifier the same unique value, because verifiers can use that value to link your presentations.

statusListIndex is a unique value.

If the holder discloses the status entry in each presentation, each verifier gets https://issuer.example/status/3#94567. That string identifies one credential, and thus one holder. Two verifiers can compare their records and find that they deal with the same person. They need only the revocation metadata for this. The status list specification identifies this risk. It says that id, statusListIndex, and statusListCredential are global identifiers "that can be used across verifiers to correlate subjects".

The spec also urges issuers to make status information selectively disclosable if the holder must present a credential without correlation. The selective disclosure mechanism carefully avoids a correlatable identifier. But the status check gives one to each verifier anyway.

This is not really a defect in the status list design. It is a result of the problem itself. A verifier that must check if this specific credential is revoked needs a value that identifies this specific credential. Status lists give herd privacy against the issuer. They give almost no privacy against verifiers that collude.

Each available response has a cost:

Accept the risk. For many use cases, verifier collusion is not in the threat model. For example, an employer and a bank can both verify the same professional license. Realistically, they do not combine their logs. If you accept the risk, write this explicitly in the threat model, and do not leave it implicit.

Disclose the status entry selectively. The specification itself suggests this. The credential carries the status information as a selectively disclosable claim. Then the holder shows it only to verifiers that require a status check, not to all verifiers by default. This decreases the exposure but does not remove it. Each verifier that does a check still gets the same index.

Per-verifier credentials. Issue a different credential, with a different status index, for each relationship between the holder and a verifier. Then the verifiers have no common value to correlate. The costs are more issuance and a much more complex issuer. Also, the issuer now knows exactly which verifiers the holder deals with, so the privacy problem moves to the issuer and does not go away. Token Status List RECOMMENDS a related method, batches of one-time-use tokens, and states that this method "does not prevent traceability by Issuers."

Short-lived credentials. Do not use revocation. Issue credentials that are valid for hours or days, and issue them again when necessary. A credential that expires quickly does not need a revocation check, so it has no index to correlate. This is a good answer where it fits. The EUDI Wallet Architecture and Reference Framework accepts short-lived attestations, with a validity of 24 hours or less, as one of its revocation methods.

Short-lived credentials have two costs. First, the holder must be able to reach the issuer regularly, and this prevents offline use. Second, the issuer sees a request for a new credential in each period. That request is a separate correlation channel, and it gives the issuer much more information.

Cryptographic accumulators. A holder can prove membership in zero knowledge. Thus, the holder shows that the credential is in the set of credentials that are not revoked, and does not show which member it is. From a technical view, this answer is good, because it fully removes the correlation value. The costs are real:

  • The cryptography is more complex.
  • The holder must keep its witness current when the accumulator changes.
  • The tools are much less mature than a bitstring and a GZIP call.

No option is free. The correct choice depends on three factors:

  • If your threat model includes verifiers that collude.
  • If your holders can be online.
  • How much cryptographic complexity your implementation can support.

Where a Bitcoin Anchor Helps, and Where It Does Not

This series is about Bitcoin. Thus, it is necessary to examine if an anchor on Bitcoin helps.

It helps with one specific problem, equivocation. A status list is a signed document on a URL, and an issuer can serve different versions to different parties. An issuer can also secretly change the history, so that a credential seems to have no revocation at any time. If you anchor a commitment to each published status list, you get a tamper-evident record of what the issuer published and when. Then a verifier can check two things: that the issuer signed the list, and that this list matches the commitment for that time. This is useful for high-value credentials if you do not fully trust the issuer.

An anchor does not help with the privacy problems. With a hash on Bitcoin, the issuer can still see the fetches. Verifiers can also still use statusListIndex as a correlation value. Those are properties of the status check, and a commitment on-chain does not change the status check.

An anchor also has a cost. Each status list update becomes an on-chain commitment with a fee. The fee causes issuers to put many updates into one batch, and thus revocations take more time to reach verifiers. An anchor is a good fit for credentials with rare revocations and costly disputes. It is a poor fit for credentials that the issuer revokes frequently.

Practical Guidance

If you design revocation for a credential system now:

  • Decide if you need revocation at all. For online use cases, short validity periods remove the problem. Examine this option first, not as a fallback.
  • If you need revocation, use the status list that matches your credential format. Use Bitstring Status List for W3C Verifiable Credentials. Use Token Status List for SD-JWT VC and mdoc. Both specifications are clear, and their herd privacy design is sound within its stated limits.
  • Use a small number of large lists. Do not divide lists by customer or credential type, unless a specific reason is more important than the smaller anonymity set.
  • Assign status list indexes randomly, not sequentially. The spec RECOMMENDS random assignment. With random indexes, a position does not easily show the issue date of the credential or the size of the group. The herd exists to hide much of this information.
  • Make a distinction between suspension and revocation in the data model, even if your current policy uses only one. It is difficult to add the distinction later.
  • Set the verifier cache interval intentionally, and write down the reason. That number is your revocation delay, and it also sets your resistance to correlation. The data model has a property for it: an optional ttl value in milliseconds on the status list credential. If the ttl is not present, the spec says that "no default value is assumed". The spec also RECOMMENDS that publishers align the HTTP Cache-Control header with the ttl value. Publish the number, and do not let verifiers guess it.
  • Serve status lists from a CDN that you do not operate. The Generate Algorithm RECOMMENDS that issuers publish status lists in a way that does not track who fetches them. One of its examples is "a content distribution network that is not operated by the issuer", and another example is Oblivious HTTP. If you operate the CDN yourself, the access logs move to a different location, but they continue to exist.
  • Write down if verifier collusion is in your threat model. If it is, plan a budget for accumulators or per-verifier issuance. Status lists alone do not give protection against verifiers that collude.

Conclusion

Revocation shows what a credential system actually optimizes for. Bitstring Status List and Token Status List are good designs. They solve the privacy problem on the issuer side well. They do not solve the problem of verifiers that collude. When you know which of these problems you have, the decision becomes much simpler.

Remember this principle: revocation is not a feature that you add to a credential system later. It affects the credential format, the issuance flow, the network behavior of the verifier, and the privacy properties of each presentation. Design revocation at the same time as issuance. If you do not, you must later choose between a system that cannot revoke and a system that leaks data.

Next week, we examine the other durability problem in a btcr2 deployment. Commitments that you anchor on Bitcoin stay there permanently. The sidecar data that explains them does not stay, unless a person takes responsibility for it.

Jintek LLC