NFTs for ticketing: when scarcity matters

Often the first application of a technology turns out to be its worst proving grounds. During the 2021 crypto craze, NFTs have achieved dubious notoriety as one of the more inane use-cases of blockchains. Pixelated images of primates trading for outsize sums invited comparisons to the Dutch tulip mania. Once prices crashed many of the so-called “collectors” were left holding the bag as schadenfreude spread in other quarters. As difficult as it may be to suggest resurrecting NFTs with a straight face today, there is a good case to be made for ticketing. This application has not been tried on any commercial scale outside of limited trials. More importantly recent landmark litigation officially labeling Ticketmaster a monopoly may finally provide an opening for new entrants in an otherwise concentrated industry.

Solid foundations: fungibility and on-chain tokenization

Sometimes the first application of a technology an industry gets wrapped around the axle on turns out not to be the optimal one. (See QR codes before the pandemic, secure-elements on mobile devices for NFC payments…) The original enthusiasm around NFTs for digital art follows that pattern. Before NFTs, there were FTs— fungible tokens, without the leading negative. As one of the earliest standards building on Ethereum, these had already proven useful in the issuance of secondary assets on the Ethereum blockchain, especially those intended to mirror an existing fiat currency such as the US dollar. Tether and Circle already boasted billions of dollar-equivalent stablecoins as ERC-20 fungible tokens in circulation before the pandemic. With the passage of the GENIUS act officially recognizing and regulating stablecoin issuers, these tokens are ever more tightly coupled with the traditional financial system, much to the chagrin of cryptocurrency detractors.

Stablecoins are meant to be fungible in the same way cash is: a dollar bill in paper currency has no unique properties to differentiate it from another bill. That also holds for bars of gold or shares of stock. But there are other types of assets where this is not true: real-estate is an example. If there are two adjacent houses in some suburban planned community with cookie-cutter construction that are identical in every aspect including their selling, the titles for those houses are still not interchangeable. The buyer of the house on the left can not legally move into the one on the right by arguing they are indistinguishable. Non-fungible tokens standardized by ERC-721 took the next logical step for tokenization— mirroring real-world assets on-chain— by introducing a variant of ERC-20 intended for one-of-a-kind objects. There is nothing fundamentally unsound about this step. It still requires the present of a trusted third-party to enforce the correspondence between on-chain representation and real world possession, but this is no different than stablecoins. One USDC stablecoin is accepted as a substitute for one traditional dollar on DeFi markets because of the belief that Circle— the company issuing USDC— is willing and able to exchange the virtual dollars for real ones in a bank account. That belief is not enforced by any consensus rules of Ethereum: it requires positing the existence of those dreaded trusted-third parties that blockchains were supposed to eliminate. Putting aside the irony, it is clear that network participants have been willing to make that leap of faith— even in the presence of evidence suggesting the stablecoin issuer has less-than-stellar reputation. Once that level of confidence exists, it is only an incremental jump to believe that some other trusted third-party can also enforce the connection between real-world property ownership and their virtual representations on chain.

Nonexistent scarcity

It was not the failure of a trusted-third party that resulted in the first NFT gold-rush turning into an easily ridiculed tulip-bulb craze. (At least, not a failure in the traditional sense of failing at their primary responsibility: maintain the correspondence between the real-world and its on-chain reflections. Investigative journalists have uncovered plenty of cases of digital art purveyors acting with less than stellar ethical standards in marketing and price-manipulation.) The fundamental problem with encapsulating public digital art in an NFT is that by definition such art has no scarcity. There is exactly one authentic instance of The Birth of Venus. It is located at the Uffizi. Laying eyes on the original involves a non-virtual trip to Florence. Any one can create a copy of that original, complete with the appearance of age by using paint and materials approximating their 15th century equivalents. Those copies are decidedly not interchangeable with the original. An art museum could conceivably create an exhibition out of replica paintings to spare visitors the inconvenience of having to travel to Italy. But no one could mistake that for actually seeing the real thing by Botticelli, any more than walking down the Las Vegas strip qualifies as having “visited” the pyramids, the Eiffel Tower and the Statue of Liberty all in the same day because simulacrums of these objects have been recreated there.1

What the proponents of digital-art-as-NFT have struggled to articulate is the answer to the question: what distinguishes one copy of the image from another? When anyone can visit the same web-page to view the exact same image— pixel for pixel identical to what all other viewers are observing— what benefit does “ownership” of the associated NFT exactly confer? It is not even bragging rights about patronage of the arts or demonstrating refined personal aesthetic, even if one takes the cynical view of modern art as a Veblen good. Having an original Picasso on the wall creates an experience that is not available to anyone else not in possession of that specific artwork, for example being able to admire said painting while having dinner with friends. If the painting is later sold, that experience is no longer available. What benefit accrues to the present “owner” of a digital-art NFT that is not accessible to anyone else who accesses the same image and downloads it locally?

Artificial scarcity

When there is no intrinsic scarcity, producers are motivated to artificially prop-up prices by creating the appearance of scarcity. This is why new mints of NFTs must be carefully controlled in quantity: there is no reason a batch of NFTs could not feature a million variations on the same theme, but justifying sky-high valuations is (relatively) easier when the marketing collateral can drum up FOMO by predicting the “limited run” will sell out in a matter of hours.

Other NFT projects attempted to sidestep this problem in a creative fashion: make-up new benefits exclusively available to holders of their NFT line. For example, events where attendance is conditioned on current ownership of a BAYC. While this type of red-velvet-rope treatment certainly creates a distinction between the NFT-haves and have-nots, it raises a question on what digital artworks have anything to do with the benefits. Why not simply auction off attendance rights to the event directly? Having a low-resolution simian image attached to the on-chain representation of that right does not appear to add any value, certainly not one to justify the large difference in price based on the exact characteristics of the same image.

Ticketing

That brings us to the pedestrian business of event ticketing, back in the headlines briefly after a federal jury in New York officially branded Ticketmaster/LiveNation an illegal monopoly. It is unclear whether any structural remedies will follow from this decision but there is a fighting chance that new entrants may be able to challenge this incumbent monopoly now operating under the watchful eye of regulators. Ticketing turns out to be a much better fit for NFTs for several reasons:

  1. Real scarcity. There are only so many seats at Madison Square Garden and so many calendar days in a year when Bruce Springsteen can perform. This is the ultimate constraint event promoters must contend with, even if they are constantly trying to create additional scarcity to squeeze even more profit. (Why are there only 100 “VIP packages” that come with mass-produced souvenir schlock when one could just as well have made 1000 copies? Why is that benefit a function of seating close to the stage when it could have been decoupled from location and made available to all fans even in the nosebleed sections?)
  2. Unsolved trust problem. It is difficult to resell tickets in a peer-to-peer manner without a centralized platform to coordinate the transactions. Direct sales between individuals would be rife with fraud because the recipient can not verify the authenticity of what they are paying for. Anyone can create a PDF or even print a piece of paper that looks like a valid ticket to a highly-coveted World Series game. But can a seller convince prospective buyers that this piece of paper is authentic? Even if it is authentic, what if they had already “sold” the same ticket to multiple people already? (This is the real-life version of the double-spend problem that bitcoin has solved elegantly.) In economics this type of information asymmetry between buyers & sellers is known to result in an inefficient dynamic called “the market for lemons” inspired by the used-car sales dynamic. Buyers artificially discount the price they are willing to pay for a car when there is a significant chance it will turn out to be a lemon worth much less than the asking price— a condition that only the seller has visibility into. This is the problem SeatGeek, Stubhub and other online market places for ticket resales solve for. It allows buyers to transfer the risk: they will be made whole for the occasional counterfeit ticket purchased from the platform, a guarantee that does not exist when directly transacting with the seller.
  3. Lack of transparency in secondary-markets. While Stubhub and its ilk have built lucrative businesses around this risk-transference model, consumers are worse off from a pricing perspective. These secondary markets thrive on opacity: while a buyer may know exactly which seat they are paying for— and thanks to federally mandated all-in pricing, how much the platform is earning in fees— they have no clue about the original face value of that ticket, much less its resale history. Is this a professional scalper charging triple price for a random batch of tickets they purchased mechanically using a bot? Or die-hard fan trying to recoup the cost of their tickets after some unforeseen life-event derails their plan to watch their favorite artist live? The distinction matters even when we acknowledge the supply/demand dynamics: artists often deliberately underpricing tickets for good-will result in a secondary market closer to fair value. Opacity props up the demand side: knowing that they are about to get ripped off by a seller demanding a ridiculous multiple of the face-value is likely to influence how much one is willing to bid. (Of course Ticketmaster and Stubhub have zero incentive to “fix” that problem and make the market more efficient: buyers getting ripped-off is good for business when the revenue depends on collecting a fraction of the sale price.)

What NFTs can and can not solve

Looking at each of the structural problems with the market, NFTs obviously can not solve the intrinsic scarcity problem: minting more NFTs on-chain does not create more seats in the stadium. Virtual tickets can only mirror this scarcity. But they solve for the trust problem in a very robust, cryptographic manner, far better than what paper tickets or animated QR codes can achieve. It would be trivial to check that a given address is the official holder of a particular NFT. Since each NFT is associated with a URL, it is also possible to look up exactly what that NFT corresponds to in real life: attendance rights for a specific seat at a particular event. Crucially that URL may hold the piece of information Ticketmaster and its ilk desperately strive to withhold from consumers: the original face-value. With some standardization around how tickets are encoded, it becomes possible to index inventory on-chain and track distribution in real-time.

To be clear: there is still a trusted third-party involved— the issuer of the NFT must be authoritative for real-world allocation of those tickets. They are in a position comparable to stablecoin issuers: they guarantee interchangeability between the virtual construct on-chain and the real life privilege of sitting at that seat. Initially this role may well end up being the same Ticketmaster/LiveNation monopoly, resulting in no structural market change for primary sales. (Just because tickets can be issued on-chain does not mean the Boss will throw away all existing distribution channels and farm out this crucial side of the music business to random upstarts.)

But the existence of tickets in NFT format could drastically reshape the secondary sale market. It is no longer necessary to have Stubhub sitting in the middle of every transaction to guarantee the authenticity of tickets, or more accurately, to refund buyers in case those tickets turn out to be counterfeit. This lowers the barriers to entry for creating true peer-to-peer marketplaces, including potentially ones operating entirely on-chain. Just as decentralized exchanges allow trading cryptocurrencies directly with a smart-contract, a decentralized ticket resale platform can enable buyers to bid on inventory. Interestingly none of the usual criticisms of DeFi platforms—that they are too slow, too expensive per transaction and susceptible to front-running compared to centralized exchanges— apply to this scenario. On-chain transaction fees are significant for an automated strategy executing thousands of trades with gains/losses are measured in cents. That is not how ticket resales work; hedge-funds are not built around high-frequency trading of tickets. If anything, introducing additional friction to handicap professional scalpers is arguably a feature. It is not possible to arbitrage across different markets: there is no “hedging” one’s exposure to holding Bruce Springsteen tickets by “shorting” Taylor Swift tickets for a different date.

Limits of transparency

For all these advantages, there is still no guarantee that NFTs can bring about full transparency or efficiency around secondary-sales. There are two reasons, one that is fundamental to all unregulated peer-to-peer sales and one contingent on the exact structure of these hypothetical marketplaces that emerge.

The intrinsic limitation is around the possibility of manipulating prices with bogus sales. Seller Alice can collude with her friend Bob to “sell” her ticket at an artificially inflated price, paying Bob under the table for his costs. (If all activity is taking place online, there is no need for Bob the co-conspirator: Alice can just create a second wallet address to bid on her own listings. This is the standard practice for artificial pump-and-dump schemes.) Bob can then list the ticket himself or hand it back to Alice: rinse and repeat. Or if Alice has a batch of tickets in the same row, inflating the price of one may now justify a higher price for the others. No money has exchanged hands and no meaningful economic activity has taken place here. But this fraudulent transaction distorted the price signal, by creating the appearance of those tickets being worth more than their fair market value. In regulated markets this type of activity is strictly illegal; the market operator is tasked by law with surveilling their platform and reporting on questionable trading patterns. Ticketing already plagued by a class of professional bottom-feeding scalpers, is unlikely to merit any significant scrutiny around market integrity.

The second limitation is a function of how much transparency the new platforms choose. Even today there is no reason that Ticketmaster could not disclose the entire transaction history associated with a ticket: issued at this face value, resold on such date for a second price, that buyer then turning around to sell it again later for a different price. To the extent that such prices are known to platforms, they are not surfaced publicly. It is possible that no single platform has necessary visibility to reconstruct that timeline: in a competitive marketplace, each resale could have taken place on a different service, each one jealously guarding its internal hoard of transactions. In reality, given the highly concentrated oligopoly that exists today, chances are a single ticket spends its entire lifetime within the confines of the same platform. The challenge is not lack of information; incentives favor keeping consumers in the dark. Those exact incentives operate even when tickets are represented as NFTs: while the object being traded exists on-chain, the transaction itself can still take place off-chain on a garden-variety website. This is very similar to how NFT sales were often conducted: buyers escrow their NFT with the platform, buyer pays the platform which arranges for transfer. While the blockchain will record the change of ownership, there is no guarantee that it will also reflect exactly how much money changed hands in the other direction. Such transparency is more likely if the platform operates entirely on-chain and each NFT transfer is accompanied by some other visible record of cryptocurrency movement in the other direction.2

CP

1 In fairness, the Vegas simulacrums are not identical in dimensions or construction to the real object either.

2 It would be possible to hide the payment using smart-contracts if buyer and seller can agree on a specific condition to be enforced by the contract for releasing the NFT. This is not quite the same as outright price manipulation. It can be rational for both parties if the seller is trying to save face and move inventory without signaling declining prices to the broader market.

Reckoning with address reuse: the post-quantum challenge for Bitcoin

Backed into a corner

Blockchains are confronting the challenge of quantum computing with renewed urgency as more researchers continue to sound the alarm. Denial is giving way to anger and bargaining. As the first and largest cryptocurrency, Bitcoin has always benefited from a certain immunity against criticism over its original design decisions and selection of features— or lack thereof, as critics frame it: rudimentary scripting language and stubborn refusal to accept even simple improvements that restore pre-existing functionality. Defenders see the intransigence and allegiance to 2008-vintage design as a virtue: sound money must be resistant to fads, very difficult to change except by near unanimous consensus of the community. Constantly hard-forking to jump on the latest smart-contract bandwagon or implementing the most fashionable signature algorithm of the day is the last thing users need. In the extreme, this becomes a version of the originalism doctrine from US jurisprudence: every contentious question is adjudicated by deference to historical pronouncements from Satoshi.

The specter of cryptographically relevant quantum computers (CRQC) is bringing some of those ancient design relics back into sharp relief. If the engineering challenges around quantum computers are overcome anywhere as quickly as optimists are predicting, the security guarantees of Bitcoin and virtually every other cryptocurrency will be immediately undermined. That often-repeated self-custody mantra “your keys, your coins” starts to ring hollow when a quantum computer can turn your keys into their keys. This is the problem every blockchain must contend with. There are some incremental solutions such as minimizing address reuse. These are not realistic, for reasons discussed in following sections. There is widespread agreement on principle that the only long-term defense against CRQC is the adoption of new signature algorithms purpose-built to resist known quantum capabilities. The engineering challenge is deciding which one— or which options, if one fully embraces cryptographic agility and giving users an option among multiple competing algorithms— and exactly how these new capabilities will be phased into an unruly system with no formal governance model. The challenge for Bitcoin is that all options on the table pose the same problem: signatures or public-keys will take up significantly more space on chain, cutting into already scarce limits for the number of transactions that can be accommodated in each block. It turns out one of those original design assumptions will greatly aggravate that problem.

Address reuse in the original vision

To explain how 2008-era decisions have backed Bitcoin into a corner today, it is helpful to highlight one aspect of the original design. Satoshi expected that addresses would only be used once. This also implies underlying cryptographic keys are also not reused, since there was a strict one-to-one mapping between them originally.1 Every Bitcoin wallet could generate an unbounded list of new addresses from a single “seed” secret. Each time the owner of that wallet needs to receive funds, they generate a fresh address with no previous history on-chain. That would be true even when sending funds back to oneself, as part of the so-called “change output.” If Alice has an unspent output of 10 bitcoins and needs to send Bob 1 bitcoin, the remaining 9 bitcoins would be sent back to a brand-new address Alice controls, not the original source address where the funds originated.

It was privacy and not the distant threat of quantum computers that underpinned this original avoidance of address reuse. CRQC remained very much in the realm of academic research during the 2000s when core ideas underlying Bitcoin were brewing in the cypherpunk community. Regardless of the motivation, some key decisions followed from this assumption:

  • Every transaction input is signed independently. If there are 10 inputs, there must be 10 signatures. It would not make sense to have a single signature authenticating multiple inputs, since they are all going to be coming from different addresses controlled by different keys. (In theory there is another, more advanced optimization possible: called “signature aggregation,” it allows combining multiple signatures into a single signature that is in turn verified against a combination of public-keys. But this is not supported by the consensus layer either.)
  • Each signature must be accompanied by the associated public key, since there is no other way to verify whether that address is controlled by that key. Later this would extend to revealing the full redeem script, which may include multiple public keys in the case of multisig. Again this makes sense if addresses are never reused. That specific public-key or redeem script has never appeared on-chain before, so it is not possible to refer back to a previous occurrence or waste space on storing that for future use, since that address will never appear in a future transaction again.

Address reuse in reality

In actual usage of Bitcoin, it turns out address reuse has become the norm. It is not some exceptional case of opsec failure. In fact later blockchains even made a virtue of address stability. For example, Ethereum and Solana group funds by address, not by chunks of coins (“UTXO” for “unspent transaction output”) as with Bitcoin. There are good reasons for this:

1. Enforcing transaction policy. The easiest way to lose control of assets on a blockchain is key compromise— when the threat actor gets hold of the private key. A close second is when the legitimate owner is tricked into wielding that private key to sign the “wrong” transaction: one that sends funds to the threat actor instead of the intended recipient. The difference between a right and wrong transaction comes down to a handful of factors, with the most significant one being the destination address. When addresses are stable, it is easy to determine whether a given address is friend or foe. Given a list of known addresses for every potential recipient, including other wallets belonging to oneself, it becomes trivial to determine what the effect of a transaction will be: how much funds are being sent to another party, how much is returned back to the sender as “change” and what fees are paid to miners for the privilege of transacting.

This concept of address whitelisting is now table-stakes for custodial services: users commit to a list of known safe addresses ahead of time and the system does not allow transfers outside of that set. (Of course there has to be some way of adding new entries to the list, and that process is made deliberately high-friction, for example by requiring out-of-band authentication or mandatory 7-day waiting period. The threat model is that even if an attacker can impersonate the legitimate customer or attempts to coerce them into executing a transfer, they can not succeed.)

2. Proof-of-reserves. In PoR a custodial service proves to its customers that they have control of all digital assets entrusted to its safekeeping. This involves two pieces:

  • Proof of liabilities: committing to the BTC balance of every customer in a verifiable manner, including the total balance across the entire customer base
  • Proof of assets: proving that the custodian controls an amount of BTC on the blockchain that is equal or greater than the liabilities.

For all practical purposes, this second step requires not only disclosing addresses but proving that the custodian still has possession of the private keys associated with that address by signing with them. While there have research proposals for doing semi-private proof-of-assets by mixing in an additional “cover” set of addresses to obfuscate the ones controlled by the custodian, it turns out the privacy improvements are limited. A satisfactory proof also requires keeping funds at the existing addresses over which the proof was conducted. If one were to conduct the PoR by moving all funds to new addresses, it would leave open the question of whether the custodian accidentally moved funds to some address they can not control, until the next PoR demonstration when they can be moved again.2

Signature bloat

As noted, the Bitcoin transaction signing format lacks any optimizations to reduce the cost of signing multiple inputs with the same public key. This is hardly noticeable when using ECDSA because both signatures and public-keys are short: public-keys take up 33 bytes with point compression while signatures are around ~70 bytes depending on encoding.

That calculus changes with post-quantum signatures. All of the algorithms standardized as part of the NIST post-quantum cryptography effort have either large signatures, large public-keys or both. NIST Signature Zoo provides a convenient way to compare these schemes, including an option to sort by total size of public-key plus signature. That is the relevant metric for Bitcoin’s existing design where every input is signed independently and contains the full public-key. Among algorithms standardized by NIST so far, the “winner” according to that criteria is ML-DSA. At 3723 bytes for one signature and public-key, it still represents a almost 40-fold expansion in space required— and that is at the lowest acceptable security level by NIST standards. Slightly more promising is Falcon/NTRU scheme, currently pending standardization. It would reduce that overhead to ~1600 bytes, a meaningful improvement over ML-DSA but far from the status quo.

Hash-based signature schemes such as SLH-DSA fare much worse on this metric. Their public-keys are qiute compact— effectively the size of one classical hash— but signatures run into multiple kilobytes. In a world where address reuse is common, this is exactly the wrong trade-off: a public-key can be “cached” on chain to amortize the storage cost of a public-key, but every transaction must still be signed independently. Note these figures assume funds are controlled by a single key: the overhead gets worse when starting to compare more complex configurations such as multi-signature schemes where all possible public-keys must be included in the signature script. 3

Reckoning with address reuse

For Bitcoin to achieve post-quantum security without further degradation of its throughput, there are two paths forward:

  1. Double-down on the hope that address reuse can be eliminated or at least strictly bounded. If one assume only a limited number of transactions are permitted out of each address, there are purpose-built stateful hash-based “few-time” signature algorithms that are more compact than the general NIST-sanctioned stateless hash-based signatures. The trade-off is a highly brittle security model: if the number of transactions is exceeded or state is mismanaged (for example, restoring from a backup resulting in reuse of previously “spent” private-key) the result is a catastrophic failure.
  2. Accept that address reuse is going to be the norm and implement difficult protocol changes to optimize for block space given the demands of post-quantum signatures. This will likely involve a hard-fork to improve transaction verification:
  • Cache redeem scripts in unpruned UTXO, to avoid outputting the same public-key over and over again
  • Allow one signature to cover multiple inputs. This could involve consolidating inputs when they share a redeem script or supporting signature aggregation across inputs. Aggregation is a more generic, powerful technique: it works across messages signed with different keys. But it is also highly dependent on the choice of signature algorithm; not every scheme lends itself to efficient aggregation. Having a “batched” signature cover multiple inputs is more straightforward from a cryptographic perspective as it does not depend on the mathematical structure of the algorithm. On the other hand, it is more complex for interoperability with Bitcoin script, since the spending conditions encumbering an input may include additional logical constraints in addition to a signature check.

CP

1 Interestingly that is no longer true: with the introduction of Bitcoin script, it is possible to generate infinite variants of a script that effectively expresses a spending condition involving the same key. Each of those variants would result in a unique address that looks independent, until the script is revealed at the time of spend.

2 Interestingly the proof-of-reserves requirement also complicates attempts to defend against quantum computers by hiding public-keys until they are spent.

3 Incidentally this discussion ignores speed of signing and verification. As things stand, the Bitcoin blockchain can only sustain a handful of transactions per second. One modern, low-end embedded device can handily out-sign and out-verify the entire network, even with the increased computational requirements of post-quantum algorithms.

Mix-and-match: risks of serial two-factor authentication

Here is a case study from a financial institution that implemented “two-factor authentication” for remote access. Our setting is the type of old-school, on-premise, Windows shop that is nearing extinction: fixed workstations managed through Active Directory, which would have felt right at home in the 1990s along with the Macarena. In a rare concession to the novel idea of employees having to access their work PC while they are not physically in the office (credit COVID for this modern epiphany) the IT department has rolled out a VPN and enabled remote-desktop access. In order to access their assigned workstations, employees jump through two layers of access control:

  1. First, they connect to the corporate VPN, authenticating with their AD domain credentials (username + password) augmented by TOTP two-factor authentication
  2. Once on the VPN, they can use one of the standard remote-desktop clients to connect to their specific workstation, again authenticating with domain credentials.

When this enterprise is going through their ritualistic yearly review of IT controls, an auditor is very likely to ask:

“Does remote access to internal systems require multi-factor authentication?”

Based on the above description, one expects this IT department to confidently respond in the affirmative and the auditors to quickly rubber-stamp that answer after cursory validation.  The subtle flaw in this model— common to legacy systems where second factor authentication has been bolted-on to satisfy some compliance requirement without much consideration for the relevant threat model— is likely to escape notice.

Mix-and-match authentication

The core issue is a disconnect between the two different authentication steps performed in series. There is no consistency check verifying whether the user connected to the VPN is the same one connecting to a specific workstation. In other words, one can connect to the VPN as Alice using Alice’s domain password & OTP credentials, then login to Bob’s workstation using Bob’s domain password. While that may look like an edge case, it points to an intrinsic weakness: once an attacker can fully impersonate any account (second factor included) every other account is only protected by a password alone.

From the threat actor perspective: if the objective is getting access to the documents on the CEO’s workstation, it is not necessary to compromise the CEO’s second-factor authentication. Instead this “mix-and-match” combination is sufficient:

  • Password + 2FA for any random employee
  • Password for the CEO

Does this qualify as two-factor authentication? Under a charitable interpretation, the answer is yes: the attacker still has to satisfy 2FA for some employee. Under a more strict interpretation, it falls short of the intended security guarantee: they did not have to defeat the 2FA associated with the CEO account. Viewed in terms of probabilities, the situation looks much better for the attacker: in a company with thousands of employees, there is a good chance some employee will get phished for both factors or have their device compromised by malware. (At which point, even phishing-resistant authentication is useless; the threat actor can ride the active session once the legitimate user completes authentication using as many convoluted steps as necessary– tapping the hardware security dongle, connecting their smart-card or performing an interpretive dance.)

Mitigations

As with most security challenges, correctly enforcing multi-factor authentication is more challenging than bolting on the half-baked version. There are a few options here, ranging from window-dressing to fully robust:

  • Alerting after the fact: correlate VPN events against remote desktop access events. This will not prevent mix-and-match authentication but it can detect unauthorized access after the fact. Depending on the latency of aggregating logs, detecting anomalies and the maturity level of incident response for the enterprise, there is a fighting chance the breach can be contained before significant damage is done.
  • Enforce two-factor authentication on endpoints. Third-party offerings such as Duo Authentication for Windows Logon allow enforcing MFA as part of the remote-desktop logon, where the presence of the second factor counts the most. (Depending on what is accessible once on the VPN, one could even argue the original design had it completely backwards: if the only thing employees can do is access their own workstation over RDP, they would have been better off with a single-factor VPN while saving the proper MFA enforcement at the endpoint.)
  • Implement proper two-factor authentication at Active Directory layer. This is the most comprehensive solution, based on a little-known fact: AD has supported phishing-resistant two-factor authentication with cryptographic hardware for 20+ years— long before consumer-grade/watered-down FIDO & its ilk existed. Based on the standardized PKINIT extension to Kerberos and smart-cards, this is widely used in high-security environments including the US government CAC & PIV programs. Realistically, the complexity of operating a PKI and issuing smart-cards places this far outside the meager capabilities of most IT departments likely to exist within the confines of a traditional financial institution.

CP

Crafting unusable public-keys [part II]

Games with prime factors

A different avenue opens up if we focus on a different aspect of RSA keys: the relationship between the public and private exponents:

e × d = 1 mod ɸ(N)

That is e and d are multiplicative inverses modulo ɸ. Since e is usually fixed by convention to a small prime, one can ask: does such an inverse always exist?

Surprisingly the answer is no. Multiplicative inverse exists if and only if e is relatively prime to ɸ. We can estimate how often that condition fails. Recalling that ɸ is a large number, and e is prime, there is only one way they could fail to be “relatively prime: e divides ɸ. Since ɸ = (p – 1)(q – 1) that would also imply e divides at least one (possibly both) of the factors.

When p and q are generated independently as random primes, p-1 and q-1 are also effectively random. We can approximate the probability of the product being divisible by e as 1/e + 1/e = 2/e. (Ignoring the highly improbable case where it divides both of them) For e = 65537, this is less than one in thirty thousand— unlikely to be encountered unless one is generating a lot of RSA keys.

Now what happens if we deliberately choose one of the primes to trigger this condition? In that case e is no longer invertible modulo ɸ and there is no “private key” in the traditional sense. This is a necessary but not sufficient condition to render the key unusable.

Root cause

To see why traditional “private key” does not completely neutralize a public key, let’s review the mechanics of RSA encryption.

The ciphertext C is obtained from the source plaintext P as:

C = Pe mod N

So encryption involves raising the ciphertext to the e-th power modulo N. Inverting the relationship we can say the plaintext is the e-th root of ciphertext modulo N. This is the important observation: decryption involves computing e-th roots.

In the case of signatures, a signature S is related to the original message M as:

M = Se mod N

Note the similar relationship: obtaining the signature S involves taking an e-th root.

In “standard” RSA, computing e-th roots is straightforward: we raise the input to the d-th power, where d is the private exponent. For efficiency reason, this is actually done as two separate calculations: first computing the root modulo p and later modulo q, then combining the results.

This gets more complicated in our version where no such d exists, because one or both of the primes were deliberately chosen such that e divides p-1.

Here we need to distinguish between two issues:

  1. Lack of unique roots. When e divides p-1, the structure of the group changes. It is no longer the case that every element has a unique e-th root. In fact most elements do not have e-th roots. Some minority— exactly fraction 1/e in fact— have an abundance of them, exactly e for each such element.
  2. Computing those roots when they exist is no longer a straightforward process of raising the input to some suitable exponent.

If a root does not exist, that message can not be signed or that ciphertext can not be decrypted (This latter case is less likely to be encountered in practice; no such ciphertext would be generated by a valid encryption process.) That is a mathematical constraint, not a computational limitation. No future quantum-computer or theoretical Zeno machine changes that.

On the other hands, the existence of multiple roots messes with the semantics of RSA. For example ciphertexts become ambiguous. They can decrypt into different plaintexts, each of the a valid root. The recipient can not determine which one the sender had in mind. Interestingly signatures are impacted in the a different way. There will be multiple valid signature corresponding to a given message. This is no different intrinsically probabilistic signatures such as ECDSA. An adversary would be considered to have defeated the system if they can find any one of those roots to forge a signature.

That becomes a computational problem for which well-known algorithms exist. For example Tonelli-Shanks algorithm computes square roots in a prime modulus. That corresponds to the special case e=2. Since p is prime, 2 will always divide p-1 so there can not be a “private exponent” to calculate roots in the general case. Adleman-Manders-Miller algorithm generalizes that to work for any e.

Deliberately mangled RSA keys

Revisiting the problem that started this blog post, suppose we generate a deliberately malformed platform key (PK) as described in the previous section. Can users be confident that it can not be used to updated the KEK? Recall that UEFI specification requires KEK updates to be signed by the KEK, so this comes down to asking what it would take to create a valid signature using the mangled key.

Let’s posit that the “attacker” already knows the factorization of the modulus. This is a realistic assumption since the OEM generating the modulus is part of the threat model.

Recall that even with knowledge of the modulus, there are two obstacles to signing:

  1. Finding a “signable” message. Not every message can be signed because some elements have no e-th roots. However attackers are usually not limited to targeting a single message. Often they can generate variations of a message that have cosmetic differences but carry the same semantics. In the case of UEFI variable updates, an attacker can generate different KEKs in the hopes that one of them results in a signable message. In other cases the hashing scheme is probabilistic, as with PSS so it is sufficient to keep the same message and vary some random padding to generate variants. This problem lends itself to brute-force after trying roughly e steps. Each step consists of generating a candidate message, hashing it and checking the order of the resulting group element. Desired roots exist if and only if the element order is divisible by e.
  2. Computing any e-th root once a suitable message is located. Time complexity of the AMM algorithm is linear in e and polynomial in bits of the prime.

The bad news is with the default RSA public exponent of e=65537, neither of these is prohibitive. Knowledge of the prime factors allows computing roots the hard way with AMM and forging signatures. The good news is we can extend the construction to greatly increase the difficulty along two dimensions.

First, we can use large public-exponents. For example if e is selected to be 128-bits, both of the above computational problems become intractable. While it is straightforward to scale up difficulty this way, it runs into a compatibility problem: not all software implementations can handle large public exponents. (For example the Windows cryptography stack used to assume public exponents fit into 32 bits.) Some systems even mandate e=65537.

Adding primes

A different approach involves increasing the number of primes. The above example implicitly assumed the RSA modulus follows the usual rules: product of exactly two distinct primes and only p has the special structure with respect to p. Suppose q is also selected to have the property q ≡ 1 mod e.

This creates a new problem for the attacker on step #1. Recall that for a group element to have e-th roots, such roots must exist modulo p and modulo q individually Since messages are mapped to group elements by a hash function, the probability of that condition being met for each prime individually is still 1/e. But the probability that it holds for both prime at the same time is 1/e². Compared to the original design, that ratcheted up the difficulty by another factor of e.

Interestingly the difficulty level of the second step does not change. AMM still takes the same effort for each prime. It has to be done twice, once for each prime factor but that is merely doubling the effort— not a material increase in cryptographic terms. The real step-up in difficulty comes from finding a signable hash with e-th roots. With two primes and e=65537, that will now require over four billion attempts on average.

No need to stop with two primes. RSA works the same way over multiple primes. This is even defined in the standard under the heading multi-prime RSA. Meanwhile recipients can not detect how many primes went into a modulus short of successfully factoring it. It follows that our 2048-bit key can be generated as a product of three or more primes. Suppose we use eight primes of roughly 256-bits, all deliberately chosen to make e-th roots rare. Now the odds of a random group element modulo N having e-th roots goes down to 1 in 2¹²⁸. Looked another way, it would require 2¹²⁸ attempts on average to locate a valid message with a hash that can be signed.

If one is willing to use large public exponents and forego any pretense of being a valid RSA key, there is another approach in the opposite direction: use a single prime number as the RSA modulus. Unlike previous examples that look like a real RSA modulus to anyone else who can not factor the product, this case is easily detectable by running a primality test. It would also be completely insecure under ordinary circumstances; the private exponent can be computed trivially from the public exponent. But the choice of public exponent here ensure no such value exists and forging a signature is equivalent to extracting e-th roots which is intractable for large e. Surprisingly this would still maintain compatibility with existing software attempting to check for valid signatures: no major implementation checks if a peer’s alleged “public key” was generated properly as a composite number. Meanwhile the formulas for signature verification operate the same way even in a prime group. It is not possible to forge a valid signature without solving the difficult root-extraction challenge modulo that prime.

Burden of proof

The last piece of the puzzle is proving that a given RSA key was generated according to the scheme described. Since the public exponent is typically determined by convention, this comes down to demonstrating the special structure of the modulus.

The exact difficulty of the proof depends on the approach taken. Single prime is the easy case, because no proof is required. Anyone can verify that the modulus N is a prime and observe its relationship to the public exponent.

For composite modulus, the standard approach involves zero-knowledge proofs. There is work going back to Bellare and Yung [CRYPTO 1992] for proving properties about a given RSA key in zero-knowledge, specifically that it defines a valid permutation. In our case, that is false by construction: public-exponents are chosen to guarantee it is not a permutation and that many elements map to the same image under the public-key operation. More recent work such as Goldberg et. al. [2019] extends that result to construct non-interactive proofs that a given N is the product of two prime powers or that it is square-free (eg no prime factor is repeated.) Since these protocols only involve the modulus and not the public exponent, they can serve as building blocks. But there is still a missing piece around proving that for every prime p that divides the modulus, we have p = 1 mod e for the public exponent e.

For the case when the modulus consists of many small primes, there is a more direct approach around revealing the factorization. Recall that the heuristic argument for difficulty above is based on an attacker already knowing the factorization. When there are many small prime factors (to keep the public exponent at 65537 for compatibility) those factors may well be within reach of ECM anyway. Even the threat model implies the security of the scheme can not rest on difficulty of factorization, because one of the “adversaries” to defend against is the person who generated modulus and has full knowledge of the factors.

CP

Brass plate engraved with 'Master Made in USA Milwaukee, WI. No. 5'

Crafting unusable public-keys [part I]

A motivating example

In modern applications it is very common for access rights to be expressed in terms of control over a cryptographic key. All blockchains operate on this model: control of funds comes down to control over a private key, usually ECDSA. Someone who can create valid digital signature using that key is assumed to be owner of those assets.

There are unusual edge-cases when a system requires such a key to be defined as part of its configuration and yet it is important to prove to third-parties that one does not have control over that key. One example is creating firmware images for secure boot. The UEFI secure boot specification defines a number of keys such as platform key (PK) and key-exchange-key (KEK) that need to be set before a system can transition into secure boot mode. Interestingly PK and KEK are not used directly validate what operating systems are allowed to boot: that is controlled by a different EFI variable, labeled database or “db” for short, which contains a list of keys or hashes. The trust chain looks like this:

PK → KEK → DB

Changes to the DB must be signed by one of the KEK entries, and changes to the KEK in turn must be signed by the PK.

Now suppose a privacy-conscious PC manufacturer wants to ship an image with DB configured in a specific way. For example, include the Microsoft third-party signing key in DB to permit Ubuntu, Debian and other operating systems with a signed shim to be installed. At the same time, this manufacturer wants to prove they do not control PK or KEK. (Since either PK and KEK allow modifying the DB, it would amount to a manufacturer backdoor into every unit shipped.) This requires creating PK and KEK entries of a particular type:

  • They must look like valid keys as far as the EFI specification is concerned; otherwise the firmware could reject them, error out or ignore secure boot configuration.
  • OEM must be able to convince customers that they do not control the corresponding private key. More specifically that they can not create signed updates to alter the KEK using PK, or alter the DB using KEK. (As we will see, “not controlling the private key” is not entirely equivalent to this formulation.)

Threat model

Proving that one knows the private key corresponding to a given public key is easy: do something that requires knowledge of the private half and which can be verified with the public key, such as digitally signing a message or decrypting a random ciphertext. Proving the negative— that one does not know it— is more tricky. Intuitively, public and private-key halves of the key are generated together, typically with the public key derived from the private key. Naively that would imply for a given public key, somebody somewhere must have known the private key.

To be clear, we want to rule out some evasions that fail to fully address the trust problem:

  • Claiming that one deleted the private-half after key generation and only retained the public piece. While such “pinky-promise” approaches may be valuable for compliance purposes and appeasing auditors, a mathematical guarantee is much preferable.
  • Claiming someone else unaffiliated generated the key. For example one could pick the public-key from Google’s TLS certificate, asserting he/she does not have the corresponding private key. While that would be a plausible statement— unless the speaker is affiliated with Google— it does not side-step the trust assumption: someone still has the private key and retains a backdoor into any system where that public key is installed. It merely deflects the problem to another trusted third-party (Google) along with a dubious theory about that entity being more competent or trustworthy at key management.
  • Claiming ownership of the key is distributed among a group of trusted third-parties where some minimum quorum must collude for any successful use. Again this does not lift the assumption of good faith, only diffuses it from a single trusted third-party to a coalition of thereof. This rules out approaches such as distributed/join key generation.

The ideal solution is one where one can offer a public key and demonstrate that no person or group ever had access to the private key.

Easy case: ECDSA

If one is willing to depart from standard key generation procedures, it is not too difficult to achieve that goal for some public-key cryptosystems. For example in the case of ECDSA, we have:

  • The private key is a plain integer (called “scalar” in EC terminology) between 1 and the order of the elliptic curve
  • The public key is a point on the curve

For a properly generated key, these two have a relationship: the public key is equal to the product of the secret scalar with a fixed point on the curve, called the “generator” because every point on the curve can be reached by taking successive multiples of that point. It follows that traditional key generation works by:

  1. Randomly selecting a private scalar from the appropriate range
  2. Multiplying that with the generation point to get the public point

What if we invert this sequence? Choose a curve point in a semi-deterministic way (more on this below) without knowing the scalar. The logical next step would be working backwards towards the private key, by calculating the scalar which would yield that point when multiplied by the generator. This is an instance of the “discrete logarithm” problem, akin to an analog of division over finite groups. But that runs up against a practical yet insurmountable problem: solving discrete logs over the type of large curves used in cryptography is computationally out of reach of present systems. In fact the security of every public-key system depends on such an assumption: deriving the private-key from the public-key must be “infeasible” in the sense that requires an amount of computation far beyond what is possible given present day understanding of the mathematics and state-of-the-art technology.1

So if we can prove that the public-key was selected according to a verifiable procedure, it provides high confidence that the corresponding private key is not known to anyone. There are several ways to do this in a nothing-up-my-sleeve manner starting with an English language statement or the digits of pi as the seed.

  • Use a cryptographic hash function such SHA256 to map the seed into a curve point. There are some nuances here. Curve points are ordered pairs <x, y> in a particular range satisfying the curve equation. While the hash output can be used to select x, there is no guarantee that a corresponding y exists. There may be no such point on the curve with that x-coordinate, or there will be exactly two requiring a choice between them. As such combining the hash operation with an incrementing counter may be necessary until a valid point is found.
  • Alternatively use a dedicated hash-to-curve scheme. These are designed to map inputs exactly into curve points of unknown discrete logarithms, without the awkward trial-and-error approach of using a plain hash.

It is important that the choice of seed be free of arbitrary decisions as much as possible. For example a seed containing a very specific sequence of digits with no explanation is bound to raise suspicion. Perhaps the prover “cooked” the seed: they tried trillions of variations on those digits until hitting on a curve point where the discrete logarithm problem was easier to solve by sheer chance. (To be clear: there are presently no such known shortcuts or concept of “weak keys” on ECDSA where one out of a trillion public keys is much easier to break.) By comparison the starting digits of pi are effectively a fact about the universe that no prover can influence.

Difficult case: RSA

Returning to the motivating example for this blog post, it turns out that most UEFI implementations do not handle ECDSA keys very well. RSA being the least common denominator for a portable solution, we run into a problem: RSA is not easily amenable to the previous approach of deterministically selecting a public-key without worrying about the private half. In effect there is shared structure linking the halves:

  • Private key is (N, d) where N is the modulus, a product of two large primes
  • Public key is (N, e) with N same as before and e the inverse of d modulo ɸ(N) the order of the multiplicative group.

In practice key generation proceeds as:

  1. Find two primes p and q of appropriate size to generate the modulus N = p × q
  2. Public exponent e is often fixed by standards or convention, for example 1 + 216 is a popular choice.
  3. Private exponent d is then calculated from e, using the known factorization of N.

If one generates N according to this sequence, then at some point that person knew the individual factors p and q, and could have used that knowledge to calculate the corresponding private exponent d. Meanwhile generating N naively in a deterministic way by hashing an agreed upon seed does quite provide the same security guarantee.

Recall that the security of RSA rests on the difficulty of factoring the modulus. Proper RSA moduli are generated as a product of two roughly equal size primes, and have exactly those two factors. By comparison, a random number of the same size is extremely unlikely to have such a clean structure. Suppose we were were to pick a random 2048-bit number and declare it to be an RSA modulus. What are the odds that number can be completely factored? Emphasis on complete factorization because deriving the private exponent from the public one requires full factorization of the group.

Factoring in the factors

If we interpret “random” in a strict sense, we can say that half the time, that number will be divisible 2. About a third of the time, it will be divisible by 3. More generally for a given “small” prime w, the number will be divisible by that prime 1/w of the time. Whether or not factoring such a composite is feasible depends on, well, many “factors”— specifically the size of the second largest factor.

There is mixed news here. Good news in that statistically speaking large numbers are also likely to have larger factors. More precisely, there is a measure called “smoothness:” a number is called B-smooth if all of its prime factors are less than B. For any given B, the probability of a randomly selected number being B-smooth rapidly declines with the size of that number. So it is astronomically improbable that our random 2048-bit number factors cleanly into a bunch of 32-bit integers, requiring no fancy factorization algorithm beyond trying the first few billion primes.

But there are specialized factoring algorithms for chipping away at small factors, specifically the Elliptic Curve Method or ECM which can reliably get at factors in the ~200 bit range. So the relevant question becomes:

“Given a random N bitnumber, what is the probability that its second-large factor is W bits or less?”

for various choices of N and W. It turns out this probability is not at all negligible for reasonable choices. For example if we use the common 2048 bit RSA key size and 200 bits as the threshold for ECM factoring, Claude Opus 4.6 estimates 1 in 5 chances of complete factorization. Even with key-sizes cranked up to 4096 bits, there is still non-negligible probability over 1%. Those are not at comforting odds for a cryptographic application.

There is another practical problem with this approach even if one is willing to roll the dice on probabilities: it is unclear how one could convince everyone else that the chosen modulus can not be factored easily. At best one can say “we ran ECM for X hours and it failed to find any factors.” That is a not a very reassuring statement. It offers little confidence that the next person trying a little harder with more computing resources could not successfully discover one more factor.

[continued in part II]

CP

  1. Granted both of those can advance. While the mathematics behind discrete logarithm problem have been studied for a long time with only incremental progress in attacks, it is entirely possible that the second dimension— computing technology— will experience a drastic leap with the introduction of quantum computers. ↩︎

Fully reversible: stablecoins and asset-seizure on chain

Reversing irreversibility and censorship-resistance

Stablecoins have made a major stride towards legitimacy with the signing of the GENIUS Act. That makes it a good time to visit some of the more surprising ways stablecoins differ from their underlying blockchain.

Two commonly cited advantages of blockchains are:

  1. Censorship resistance. By virtue of being a decentralized system, there is no government regulator or other authority in a position to decide who can transact on chain. It is not possible to “seize” funds or systemically exclude disfavored persons from the financial system.
  2. Irreversible transactions. Once the transaction is confirmed, it can not be undone. Unlike credit cards payments or ACH transfers, there are no disputes, no charge-backs or other avenues to claw back funds.

Whether these are features or bugs is in the eye of the beholder. Empowering individuals excluded from the banking system for politically reasons sounds noble— until that individual turns out to be Kim Jong-Un trying to finance a rogue nuclear weapons program. Likewise, finality in payments may seem very appealing to anyone accepting credit cards today. It is well known that scammers can pay for goods with a credit card and later contest the transaction in bad faith. That leaves the merchant holding the bag by default, or at least with the burden of proving that the buyer did indeed receive the services they were charged for. That may look like a raw deal for the merchant but consumers appreciate the value of such reversible transactions when they experience theft of digital assets, only to be told by their exchange/custodian that nothing can be done to recoup their losses.

Putting aside value judgments on irreversibility, there is one little-noted fact about stablecoin transactions: they are neither censorship-resistant or irreversible as a matter of necessity. This may come as a surprise. Stablecoins are built on top of blockchains lauded for having exactly those properties. Indeed it takes all the complexity of smart-contracts and virtual machines to “solve” that problem and create a centralized, tightly supervised digital asset class on top of an inherently decentralized, permissionless foundation.

No free lunch: in stablecoin issuers we trust

Stablecoins are an example of “real world assets on-chain.” Their distinguishing feature is being convertible one-to-one to a fiat currency such as the dollar or euro. By design blockchains are hermetically sealed systems: they have no direct interactions with the banking system or any other payment network. That makes it difficult to represent ownership of arbitrary assets in the real-world. This is where stablecoin issuers enter the picture: the issuer is the trusted third-party guaranteeing convertibility between the real world asset and its on-chain representation. Send dollars to the issuer and they will “mint” an equivalent amount of the stablecoin token and credit it to your blockchain address. Going in the other direction, participants may also choose to exit the system, exchanging their tokens for dollars. In that case the issuer execute a “burn,” taking out the equivalent quantity of tokens from circulation and returns the corresponding dollars back via traditional rails, such as wire transfer.

In practice, the stablecoin issuer does not have direct business relationships with every retail investor— that could not scale. Mints/burns are initiated by a relatively small number of intermediaries in the ecosystem, such as cryptocurrency exchanges. These intermediaries make it seamless for their customers to switch back and forth between fiat currency and stablecoins, while hiding the complexity of interactions with the issuer. Depending on the arrangement, they could also charge fees for the convenience or alternatively collect incentive payments from the issuer. Stablecoin issuance is a lucrative business, especially in a high interest regime. The issuer gets to collect interest on the fiat held in reserve. Since every dollar worth of stablecoin on chain requires a dollar held in an account by the issuer (for convertibility to work) the issuers profits correlate directly with the total outstanding amount in circulation. Conversely, it is a lousy deal for anyone to hold stablecoin when they could instead park the equivalent amount in fiat and collect the interest themselves.

In a 2001 essay titled “Trusted third-parties are security holes,” Nick Szabo called out the risks created by outsourcing critical roles in financial systems to allegedly trusted entities such as credit-card networks or certificate authorities. While this argument predated the rise of Bitcoin by several years, its warnings are prescient in the context of stablecoins. The convertibility of stablecoins to their underlying fiat currency is not guaranteed by any intrinsic property of blockchains. It does not matter that how decentralized the systems is and how well its consensus protocol as executed by thousands of independent nodes provides security against lone actors from disrupting the system. When it comes to stablecoins, it is 100% up to a single actor in the system—the stablecoin issuer— to link virtual dollars on-chain to real world dollars in a bank account.

It is easy to imagine ways that link can fail:

  • The issuer can embezzle funds and vanish.
  • It can deliberately issue more stablecoins than are held in reserves. That is, issue excess supply tokens without any fiat backing. Absent independent audits, the discrepancy could remain undetected for a long time, until some financial crisis results in a “run” with everyone trying to withdraw fiat out of the system, only to discover that the issuer cannot meet all redemptions.
  • That same situation can arise due to incompetence instead of malfeasance: the issuer may experience a security breach of their systems. If a threat actor gains control of the on-chain “money printer” they can mint new tokens for their own benefit without any fiat backing.
  • Instead of investing the reserves in low-risk assets such as treasuries, the issuer can roll the dice with dubious schemes and lose money, once again resulting in net deficit of fiat against virtual token.

All these cases lead to the same outcome: the stablecoin is no longer “full-reserve.” If all participants tried to convert back to the underlying currency, some of them would not get paid in full. Until recently, none of this was helped by the opacity of issuers operating in the Wild West of finance. In particular Tether, by far the largest issuer of dollar stablecoins with more than $100B outstanding, has been at the center of multiple controversies over its reserves and inconsistent statements. That includes a finding by NY state that at least during one stretch of time Tether was not fully backed. Time will tell if the newly enacted GENIUS legislation in the US will change this state of affairs and compel more transparency out of issuers.

For the remainder of this blog post, we put aside the ongoing shenanigans at Tether and focus on a hypothetical issuer that maintains full fiat backing of their assets, prudent in investing that fiat and competent at protecting against security threats. What are the risks posed by this ideal trusted third party?

Censorship-friendly by design

The surprising answer is that for virtually all major stablecoins in existence, this issuer retains the discretion to engage in arbitrary censorship and asset seizure. In order from mild to severe in their effects, these capabilities include:

  • Preemptively block any address from participating in stablecoin transactions— effectively a form of debanking
  • Freeze funds at any address. This goes one step further than mere debanking; now the issuer is temporarily preventing a network participant from accessing existing funds. Freezes can be lifted but in the worst-case scenario funds can remain accessible indefinitely.
  • Burn funds at any address. We are now fully in asset-seizure territory. Unlike a temporary freeze on assets which may be lifted, this one is irreversible from the perspective of the participant whose funds are gone.

As a corollary to #3: stablecoin issuers may be in a position to reverse transactions. Imagine Alice sends Bob some stablecoins. This is handled by decreasing the balance for Alice’s address on the stablecoin ledger and incrementing the balance for Bob’s address by an identical amount. If Alice later disputes the transaction and the issuer sides with Alice they can simply burn the assets at Bob’s address and magically mint an equivalent amount at Alice’s source address. Presto: the funds Alice sent are restored and the ones Bob received are gone, reverting to the state before the transaction. This legerdemain has no effect on whether the stablecoin remains fully backed 1:1 by equivalent fiat reserves. No actual dollars or euros have left the system; instead their virtual representation on chain has been reshuffled to Alice’s benefit and at the expense of Bob.

Stablecoins under the hood

To appreciate the how this works, we need to establish a few facts about how stablecoins are implemented at the nuts-and-bolts level. From an engineering view stablecoin is nothing more than a special type of smart-contract operating on a contract-capable blockchain that manages its own ledger of balances. “Smart-contract” is a fancy way of saying glorified software: program or code. Due to the severe resource restrictions in the type of computations most blockchains can execute, these programs are quite rudimentary compared to a typical mobile app or moderately complex interactive website. (Constrained computing resources should not be confused with simplicity; being rudimentary has not stopped these applications from having catastrophic bugs that are exploited for millions of dollars in losses routinely.)

Not every contract represents a stablecoin. Stablecoins conform to a specific template, a least-common denominator that determines the functionality expected. Often these are standardized on a given chain. For example Ethereum has ERC-20. That specification defines the set of functions every contract representing a “fungible token” must implement. Again not every “fungible token” is a stablecoin: some represent a utility token that in theory can be used to pay for certain services on-chain. (Or so the theory went in 2017 when ICOs were all the rage for funding early-stage projects, by selling tokens ahead of time before the service in question was event built.)

For example looking at the ERC20 standard, we observe a number of functions that every stablecoin must support. Here are some of the most important ones associated with moving funds:

  • transfer: Sends funds to an address.
  • approve: Pre-approve a specific address to be able to withdraw from the caller’s account up to specified amount. This is useful for smart-contract interactions— such as placing an order at a decentralized exchange— when the exact amount to be withdrawn can not be predicted in advance.
  • transferFrom: Variant of transfer used by smart-contracts, in conjunction with the preapproval mechanism.

Oddly there is nothing in the standard about supervisory functions reserved for the issuer: minting new assets on chain, burning or withdrawing assets from circulation, much less blocking specific addresses or seizing assets. Where is that functionality? The answer is it is considered out of scope for ERC-20 standard. In software engineering terminology, it would be called an “implementation detail” that each contract is free to sort out for itself. Strictly speaking one could deploy a stablecoin that does not have any way to seize funds. Yet it is telling that all major stablecoins to date including Circle, Paxos, Gemini Dollar and even Tether have opted for building this functionality. [Full disclosure: this blogger was involved in the development of GUSD]

Case study: Circle

Let’s take a look at the smart-contract for the Circle stablecoin or USDC. Etherscan shows the token with ticker USDC is managed by the contract at address 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48. That page shows the contract has a verified source code; that means someone has uploaded source code which when compiled with a specific version of the Solidity compiler, produces EVM bytecode identical to what exists at that address. (Effectively a deterministic build process for proving that a given piece of code really does correspond to a deployed contract.) But this verified code is decidedly underwhelming, with hardly any indication of stablecoin functionality. That is because the Circle contract is just a thin proxy, a wrapper that forwards all incoming calls to an underlying secondary contract. This level of indirection is common to complex contracts on Ethereum. It allows upgrading what is otherwise immutable logic. While the proxy code can not be modified, the target contract it forwards to is just an ordinary data field that can be modified to point to a new address when it is time to upgrade the contract. (Strictly speaking, Ethereum now has a way to upgrade contracts in-place but the proxy pattern provides more control and transparency over the process. Here )

For our purposes, finding the actual implementation of USDC requires going one level deeper and chasing the value of that initial pointer. Etherscan makes this easy, as the constructor arguments already have a helpfully named argument called “implementation” which points to another verified contract that contains the real USDC stablecoin logic. This allows us to chase down the original implementation that the contract was deployed with.

Here is the functionality for freezing an address in a function appropriately called “blacklist:”

function blacklist(address _account) public onlyBlacklister {
blacklisted[_account] = true;
emit Blacklisted(_account);
}

Once an address is marked as blacklisted, all other operations involving that address in any capacity fail. It would come as no surprise that assets can not be transferred out of that address, but it is not even possible to send funds to that address as destination.

That function to mark an address as blacklisted is gated by the modifier onlyBlacklister. In the Solidity programming language, modifiers signal that some function can only be invoked when specific conditions are met. Modifiers themselves are defined by functions returning a boolean true/false indication. In the same source code listing, we can locate that function in a parent class inherited by the stablecoin:

modifier onlyBlacklister() {
require(msg.sender == blacklister);
_;
}

Translation: this function checks that the Ethereum address of the caller is identical to a predefined “blacklister” address. Not surprisingly, the blacklisting capability is not publicly available for any random person to invoke. It can only be called by a specific designated address. So who is the privileged blacklister?

Etherscan also allows inspecting internal contract state, including the values of internal variables. For example we can observe what the current the initial V1 deployment of the contract, the blacklister address was identical to the “master-minter” address authorized to issue new USDC on chain— presumably Circle itself.

Outsourcing censorhip

While minting and blacklisting address were one and the same in this example, it is worth exploring the consequence of the inherent flexibility in the contract to separate them. Blacklisting role can be outsourced to a third-party who specializes in blockchain compliance. Stablecoin issuers are already leveraging services such as Chainalysis, Elliptic and TRM for oversight of their network. In an alternative operational mode, they could just assign the blacklisting role to one of those service providers. For that matter, in a slightly more dystopian alternate universe, a government regulator could demand the role for itself.

Recall that the pointer-to-implementation pattern allow upgrading contract logic. Indeed the code linked above is not the current version of USDC. It has already gone through multiple iterations. The latest version deployed as of this writing in January 2026 is open-sourced in the Circle Github repo. That code follows the same pattern as its predecessor: an authorized “blacklister” can freeze funds as before. But there is a difference in the deployment pattern: now the blacklister address is distinct from the minter. That does not imply they are different entities. It could just be a case of sound operational security to use different cryptographic keys to manage different functions. (Considering that the minting capability is far more sensitive and allows printing money out of thin-air, one would not want to use those keys for less-sensitive operations such as blacklisting.)

We can also observe on-chain how often that functionality is invoked by looking at all transactions originating from the blacklister. The record shows over 200 calls in the past year, of which:

  • 170 are calls to blacklist
  • 36 are calls to un-blacklist, that is lift the restrictions on a previously blacklisted address

Bottom line: This is not some hypothetical functionality lurking in the contract that is never exercised. Whoever holds the blacklisting capability for USDC has been routinely invoking that privilege as part of their oversight activities on the network.

Beyond blacklisting: Tether and asset seizures

Blacklisting an address prevents it from being able to move any funds, but is not the same as asset seizure. In the case of USDC, at worst funds can be indefinitely frozen and taken out of circulation. But they can not be reassigned to another party in response to a request from law enforcement. (At least not yet— recall that the proxy contract can be upgraded and Circle can introduce this additional capability in the future.)

Tether takes this one step further and allows direct seizure. Not only does it allow blacklisting, but there is an additional capability to reclaim funds after an address has been blacklisted. By following the implementation pointer from the current version, we can locate the responsible piece of logic. Excerpted here:

function destroyBlackFunds (address _blackListedUser) public onlyOwner {
require(isBlackListed[_blackListedUser]);
uint dirtyFunds = balanceOf(_blackListedUser);
balances[_blackListedUser] = 0;
_totalSupply -= dirtyFunds;
DestroyedBlackFunds(_blackListedUser, dirtyFunds);
}

This code zeroes out the balance of the blacklisted address, removing the equivalent amount of tether from circulation. That may not look like asset seizure, in the sense that the funds have vanished entirely but that is illusory. Recall that tethers on-chain are supposed to be backed by actual US dollars in a bank account somewhere. (Although in the case of Tether, that has been notoriously difficult to verify due to the opaque nature of the operation and checkered history with regulators.) While the on-chain balances are gone, the US dollars are still sitting in the bank and free to be released to law enforcement or whoever initiated the seizure. If the authorities demanded to receive the funds in-kind, Tether could even execute a “mint” to magically have the equivalent amount appear at a specified address.

Postscript: breaking fungibility and censorship at the off-ramp

To be clear, this post is not intended to single out Circle and its compliance program. There is no evidence that either issuer has engaged in arbitrary asset seizure or randomly reversed transactions to settle scores with their competitors. By all accounts, every intervention was precipitated by a demand from law enforcement or financial regulator. For a US-based financial services company, that is the offer-you-can-not-refuse. Furthermore this functionality is not a “backdoor” or some hidden feature the stablecoin operator hoped to obfuscate. Contract implementations are open-source and every action to freeze/seize funds is visible on-chain, operating in plain daylight. In multiple cases issuers even boasted publicly about their commitment to compliance by highlighting specific instances of seizure they executed.

One would expect stablecoin issuers greatly prefer a hands-off approach to unauthorized transactions involving their asset. Hand-wringing and bromides on the theme of “code is law” are preferable to active intervention because the latter creates a lot of operational expense. In a high-interest environment, stablecoin issuance is extremely lucrative: all one needs to do is occasionally mint some large allocation of tokens when a wire transfer comes in from a handful of business partners, sit back to collect interest on those deposits and occasionally wire funds outbound when one of those partners wants to convert their stablecoin back into fiat. This business can be run with minimal operational overhead. By contrast staffing a compliance department and actively fielding requests from regulators around the world to promptly freeze criminal transactions takes a lot of work, eating into those enviable margins. (Compare that to the cost of resolving disputes in a credit-card network. No surprise stablecoin payments can be much more “efficient” than Visa/MasterCard when the former does not have to maintain 24/7 support to deal with fraudulent transactions or settle disputes between disgruntled card-holders and aggrieved merchants.) For that reason stablecoin operators left to their own devices would prefer to avoid engaging in outright asset seizure, censorship or transaction reversal, except to the extent that criminal activity becomes a reputational risk for the business. Yet the record makes it clear they have time and again staged such interventions. Even Tether, with its checkered history and popularity with organized crime groups behind pig-butchering scams, has recognized the necessity of responding to demands from regulators and seized funds on multiple occasions.

While the preceding discussion focused on direct censorship and asset seizure on chain, stablecoin issuers have another enforcement mechanism at their disposal. They can simply refuse to honor the convertibility of tokens back into real world assets.

Consider this hypothetical: some digital asset business is breached and crooks walk away with a stash of USDC stablecoin. Before Circle has an opportunity to intervene, the stolen funds are distributed to multiple addresses, exchanged into other currencies via decentralized exchanges or lending pools, maybe even bridged to other chains for USDC on Solana. There is no longer a single address where the proceeds of theft are concentrated, making seizure or freeze complicated. In fact some funds maybe sitting at a shared address such as a lending pool, mixed with other USDC contributions from honest participants in that pool. Clearly freezing the entire address out of USDC ecosystem is not an appropriate response in this situation. Even trying to manually adjust the balance by a careful sequence of burn/mint operations runs the risk that USDC will interfere with the operation of the pool. Case in point: prices on a decentralized exchange are determined algorithmically by an automated market maker (AMM) based on how much of the asset exists in the pool on both sides of the trade. Suddenly zeroing out the USDC balance can result in market disruption and wild pricing discrepancies.

A different way Circle can address this problem is by declaring that some fraction of USDC in the pool is permanently “tainted.” That USDC will no longer be considered as eligible for conversion back to ordinary US dollars, regardless of how many times it is transferred to other blockchain addresses. That last property requires Circle to maintain constant vigilance, watching for movement of tainted funds to other addresses and give them the same cold-shoulder if they ever show up demanding fiat dollars in exchange for their now worthless stablecoins. (This raises some thorny questions: which fraction exactly is tainted? If 1 USDC of stolen funds is added to an address containing 9 clean USDC and withdrawn in multiple chunks, how is the taint propagated? For technical reasons explorer in an earlier post, it turns out FIFO works better than LIFO for this purpose.)

By implication everyone else dealing in USDC must perform the same sleuthing— or more likely, outsource this process to a blockchain analytics service such as Elliptic or TRM. If Circle will treat some chunks of USDC as effectively worthless regardless of what the on-chain record says, everyone else is obliged to treat those tokens as worthless. This creates an insidious type of shadow-debanking: participants holding tainted stablecoins are free to transact and move those funds on-chain freely. But the moment they head for an off-ramp to convert those tokens to real-world dollars, they will discover their holdings are worthless. Those balances maintained in the USDC smart-contract ledger on chain turns out to be a chimera. If the only authoritative record— the ledger maintained by Circle compliance department— assigns a zero balance to an account, that account has exactly zero dollars.

CP

The unbounded development team: promise and perils of AI coding assistants

Once upon a time, there was a software engineer we will call “Bob.” Bob worked in a large technology company that followed a traditional waterfall model of development, with separation of roles between program managers (“PM”) who defined the functional requirements and software design engineers (“SDE”) responsible for writing the code to turn those specs into reality. But program managers did not dream up specifications out of thin air: like every responsible corporate denizen, they were cognizant of so-called “resource constraints”— euphemism for available developer time.

“Features, quality, schedule; fix any two and the remaining one is automatically determined.”

Schedules are often driven by external factors such as synchronizing with an operating system release or hitting the shelves in time for the Christmas shopping season. Product teams have little influence over these hard deadlines. Meanwhile no self-respecting PM wants sacrifice quality. “Let’s ship something buggy with minimal testing that crashes half the time” is not a statement that a professional is supposed to write down on paper— although no doubt many have expressed that sentiment in triage meetings when hard decisions must be made as the release deadline is approaching. That leaves features as the knob easiest to tweak and this is where developer estimates comes in.

Bob had an interesting quirk. Whenever he was asked to guesstimate the time required to implement some proposed product feature, a strictly bimodal distribution was observed with two peaks:

  • Half-day
  • Two weeks

Over time a pattern emerged: features Bob approved of seemed to fit in an afternoon, even when they seemed quite complicated and daunting to other software engineers who preferred to steer clear of those implementation challenges. Other features that seemed straightforward on the surface were recast by Bob as a two-week long excursion into debugging tar-pits.

In Bob’s defense: estimating software schedules is a notoriously difficult problem that every large-scale project has suffered from since long before Fred Brooks made his immortal observations about the mythical man-month. Also Bob would not be the first or last engineer in history whose estimates were unduly influenced by a certain aesthetic judgment of the proposal. Highly bureaucratic software development shops prevalent in the 20th century relegated engineers to the role of errand boys/girls, tasked with the unglamorous job of “merely” implementing brilliant product visions thrown over the wall from the PM organization. Playing games with fudged schedule estimates becomes the primary means of influencing product direction in those dysfunctional environments. (It did not help that in these regimented organizations, program management and senior leadership were often drawn from non-technical backgrounds, lacking the credibility to call shenanigans on bogus estimates.)

Underlying this bizarre dynamic is the assumption that engineering time is scarce. There is an abundance of brilliant feature ideas that could delight customers or increase market share— if only their embodiment as running code can see the light of day.

AI coding assistants such as Codex and their integration into agentic development flows have now turned that wisdom on its head. It is easier than ever to go from idea to execution, from functional requirements to code-complete, with code that is actually complete: with a suite of unit tests, properly commented and separately documented. “Code is king” or “code always wins” used to be the thought-terminating cliché at large software companies: implying that a flawed, half-baked idea implemented in working code is better than the most elegant but currently theoretical idea on the drawing board. It is safe to say this code-cowboy mentality idolizing implementation over design is completely bankrupt: it is easier than ever to turn ideas into working applications. Those ideas need not even be expressed in some meticulous specification document with sections dedicated to covering every edge case. Vibe-coding is lowering the barrier to entry across the board, not just for implementation knowledge. When it comes to prompting LLMs, precision in writing still matters. Garbage-in-garbage-out still holds. But being able to specify requirements in a structured manner with UML or other formal language is not necessary. If anything the LLM can reverse-engineer that after the fact from its own implementation— in a hilarious twist on another tenet of the code-cowboy mindset: “the implementation is the spec.”

There is an irony here that LLMs have delivered in the blink of an eye the damage experts had once prognosticated/feared outsourcing could wreak on the industry: turn software implementation from being the most critical aspect of development practiced by rarefied talent to a commodity that could be shipped off to the lowest bidder in Bangalore. (The implications of this change on the “craft” of development are already being lamented.)

The jury is still out on whether flesh-and-blood developers can maintain that torrent of code generated by AI down the road, should old-fashioned manual modifications ever prove necessary. One school of thought expects a looming disaster: clueless engineers blindly shipping code they do not understand to production, knowing full well they are on the hook for troubleshooting when things go sideways. No doubt some are betting they will have long moved on and that responsibility will fall on the shoulders of some other unfortunate soul tasked with making sense of the imperfectly functioning yet perfectly incomprehensible code spat out by AI. Another view says such concerns are about as archaic as fretting over a developer having to jump in and hand-optimize or worse hand-correct assembly language generated by their compiler. In highly niche esoteric or niche of development where LLMs lack sufficient samples to train properly, it may well happen that human judgment is still necessary to achieve correctness. But for most engineers plan B for a misbehaving LLM assistant is asking a different LLM assistant to step in to debug its way out of the mess.

Software designers are now confronted with a variant of the soul-searching question: “If you knew you could not fail, what would you do?” For software projects, failure is and will remain very much an option. But its root causes are bound to be different. LLMs have taken the most romanticized view of failed projects off the table: ambitious product vision crashing against the hard reality of finite engineering time or limited developer expertise failing to rise to the occasion. Every one can now wield the power of a hundred-person team composed of mercenary engineers with expertise in every imaginable specialty from low-level systems programming to tweaking webpage layouts. That does not guarantee success but it does ensure the eventual outcome will take place on a scale grander than possible before. Good ideas will receive their due and reach their target market, no longer held back by mismatch between willpower and resources, or the vagaries of chancing upon the right VC willing to bankroll the operation.

At least, that is the charitable prediction. Downside is the same logic goes for terrible ideas too: they will also be executed to perfection. Perhaps those wildly skewed schedule estimates from engineer Bob served a purpose after all: they were a not-so-subtle signal that some proposed feature was a Bad Idea™ that has not been thought through properly. Notorious for sycophancy, AI coding assistants are the exact opposite of that critical mindset. They will not push-back. They will not question underlying assumptions or sanity-check the logic behind the product specification. They will simply carry out the instructions as prompted in what may well become the most pervasive example of “malicious compliance.” In the same way that social media bestowing everyone a bullhorn did not improve the average quality of discourse on the internet, giving every aspiring product manager the equivalent of 100 developers working around the clock to implement their whims is unlikely to yield the next game-changing application. If anything, making engineering costs “too cheap to meter” may result in companies doubling down on obviously failing ideas for strategic reasons. Imagine if Microsoft did not have to face the harsh reality of market discipline, but could keep iterating on Clippie or Vista indefinitely in hopes that the next iteration will finally take off. In a world where engineering time is scarce, companies are incentivized to cull failures early, to redirect precious resources towards more productive avenues. Those constraints disappear when shipping one more variant of the same bankrupt corporate shibboleth—think Google Buzz/Wave/Plus, Amazon Fire phone, Windows mobile platform, Apple Vision Pro— is just a matter of instructing the LLM to “think harder” and spin a few more hundreds hours iterating on the codebase.

CP

On the limits of binary interoperability

Once upon a time there was a diversity of CPU architectures: when this blogger worked on Internet Explorer in the late 90s, the browser had to work on all architectures that Windows NT shipped: Intel x86 being by far the most prevalent by market share, but also DEC Alpha, PowerPC, MIPS and SPARC. (There was also a version of IE for Apple Macintosh; while those also used PowerPC chips, that code base was completely different, effectively requiring an “emulation” layer to pretend that Win32 API was available on a foreign platform.)

2000s witnessed a massive consolidation of hardware. MSFT dropped SPARC, MIPS and PowerPC in quick succession. DEC Alpha— an architecture far ahead of its time— would limp along for a little longer because it was the only functioning 64-bit hardware at a time when MSFT was trying to port Windows to 64-bits. Code-named Project Sundown in a not-so-subtle dig at Sun Microsystems (then flying high with Java, long before the ignominious Oracle acquisition) this effort originally targeted the Intel Itanium. But working systems featuring the Itanium would not arrive until much later. Eventually Itanium would prove to be one of the biggest fiascoes in Intel’s history, earning the nickname “Itanic.” It survived in niche enterprise markets in zombie-like state until 2022 when it was finally put out to pasture.)

Even Apple once a pillar of the alliance pushing for PowerPC surprised everyone by switching to x86 during the 2000s. For a while it appeared that Intel was on top of the world. Suddenly “Intel inside” was true of laptops, workstations and servers. Only mobile devices requiring low-power CPUs had an alternative with ARM. AMD provided the only competition, but their hardware ISA was largely identical to x86. When AMD leapfrogged Intel by defining a successful 64-bit extension of x86 while Intel was running in circles with Itanium going nowhere, the Santa Clara company simply adopted AMD64 into what collectively became x64. Late 2010s then represented something of a reversal in fortunes for both Intel and x86/x64 architecture in general. Mobile devices began to outsell PCs, Apple jumped on the ARM bandwagon for its laptops, AWS began shilling for ARM in the datacenter and RISC-V made the leap from academic exercise into production hardware.

Old software meets new hardware

When a platform changes its underlying CPU architecture, there is a massive disruption to the available software ecosystem. By design most application development targets a specific hardware architecture. When the platform shifts to different hardware, existing software must be recompiled for the new hardware at a minimum. More often than not, there will be source code changes required, as in the case of going from targeting 32-bit Windows to 64-bit Windows.

Unlike operating system releases, this is not a process the platform owner can help with. Consider how conservative MSFT used to be about breaking changes. The company maintained an aggressive QA process to check that existing software released for previous versions of Windows continued to work the upcoming one. Sometimes that meant being bug-for-bug compatible with some behavior going back to Windows 3.1. Deliberate changes breaking existing software were rare. That is because Redmond understood the flywheel effect between operating systems and applications. The more applications exist for an operating system, the more motivated customers are to demand that OS for their next purchase. The more popular an OS becomes, the more likely independent software developers take notice and begin to write new applications or port their existing offerings to that OS. If one operating system has 90% of market share and its competitor only has 10%, the rational choice for ISVs is to prioritize the first one. That could take different shapes: It could be that the application only ships for that OS. The revenue from that marginal 10% expansion may not be enough to compensate for the steep increase in development cost. Especially when the platforms are fundamentally different, as in Windows and MacOS, there is often very little code-sharing possible and a lot of duplicated effort. Or they could deprioritize the effort, eventually releasing a greatly scaled-back version for the less-popular OS eventually, with fewer features and less attention to quality. (Exhibit A: MSFT Office for Mac.)

That makes hardware changes a treacherous time to navigate for platform owners, threatening to break this lucrative flywheel. If the new environment does not have the same rich ecosystem of third-party software support, customers may delay upgrading until their favorite apps are ported. Or worse, they may even consider switching to a competing platform: if migrating to 64-bit Windows is going to be a radical change and result in significant changes to the corporate IT platform, why not consider going all the way and switch to MacOS?

Enter binary compatibility. Windows has multiple compatibility layers for running applications that never expected to run on the current version of Windows. For example:

  • WoW64 (“Windows-on-Windows”) allows 32-bit binaries to execute on 64-bit Windows. This is the new iteration of the original “WoW” that helped run 16-bit DOS and Windows 3.X binaries on 32-bit Windows NT/2000/XP.
  • Similar layer exists for Windows on ARM to run binaries compiled for the x86/x64 architecture

In both cases, applications are given a synthesized (fabricated? falsified?) view of the operating system. There is a “Program Files” directory but it is not the one where native applications are installed. There is a “registry” with all the usual keys for controlling software settings, but it is not the same location referenced by native applications. Called registry redirection, this compatibility feature allows application written for a “foreign architecture” (for example 32-bit applications on native 64-bit operating system) to operate as if they were running on their original target without interfering with the rest of the system.

The phantom mini-driver on Windows ARM

Impressive as these tricks are, there are limits to interoperability between binaries compiled for different hardware architectures. Case in point: this blogger recently tried using a new brand of cryptographic hardware token on Windows ARM. Typically this requires installing the so-called mini-driver associated with that specific model. “Driver” terminology is misleading, as these are not the usual low-level device drivers running in kernel-mode. Modern smart-cards and USB hardware tokens look the same at that layer, such that they can be uniformly handled by a single PC/SC driver. Instead “mini-driver” abstraction is a user-mode extensibility mechanism introduced by the Windows smart-card stack. By creating a common abstraction that all hardware conforms to, it allows high-level applications such as web browsers and email clients to use cryptographic keys in a uniform manner, without worrying about vendor-specific implementation details behind how that key is stored. Effectively this becomes the “middleware” every vendor is responsible for providing if they want Windows applications to take advantage of their cryptographic widget.

In this case the vendor helpfully provided an MSI installer for their middleware, with one catch: there was only an x86 version. No problem, since Windows ARM can run x86 binaries after all. Sure enough, the installer ran without a hitch and after a few clicks reported successful installation. Except when it came time to use the hardware associated with the mini-driver: at that point, the system continued to fall back to the default PIV mini-driver instead of the vendor specific one. (This is a problem. As discussed in previous posts, the built-in PIV driver on Windows is effectively read-only. It can use existing objects on the card, but cannot handle key generation or provision new certificates.) That means the smart-card stack could not locate the more specific vendor driver with additional capabilities. Did the installer hallucinate its successful execution?

Internet Explorer and its doppelganger

Interview question from the late 2000s for software engineer candidates claiming high level of proficiency with Windows:

Why are there two versions of Internet Explorer on 64-bit Windows, one 32-bit and another 64-bit?”

The answer comes down to one of these limitations of interoperability: 64-bit processes can only load 64-bit DLLs in process. Likewise 32-bit processes can only load 32-bit DLLs. Before MSFT finally deprecated native-code extensions such as ActiveX and browser helper objects (“BHO”, historically one of the best ways to author malware for shadowing all browsing activity) it was not uncommon for websites to rely on the presence of such add-ons. For example Java and Adobe Flash were implemented this way. But historically such native extensions were all written for 32-bit Windows and they could not have successfully loaded into a 64-bit browser process.

MSFT is notorious for its deference to backwards compatibility and reluctance for breaking changes, for good reason— it did not turn out all that well when that principle was abandoned in one bizarre spell of hubris for Vista. So it was a foregone conclusion that 64-bit Windows must include 32-bit IE for down-level compatibility; there was no way hundreds of independent software publishers would get their act together in time to have 64-bit versions of their extensions ready when Vista hit the shelves. (Turns out they need not have worried; those copies were not exactly flying off the shelves.) The concession to backwards compatibility went much deeper than simply shipping two instances of the browser: 32-bit IE remained the default browser until a critical mass of those third-party extensions were ported to 64-bits, despite all of its limitations and lack of security hardening features available to true 64-bit applications. (From a consumer point of view, one could argue the unavailability of popular native code extensions is very much a feature. With Adobe Flash being a cesspool of critical vulnerabilities, having a browser that can never run Flash is an unambiguous win for security.)

Worth calling out: this was decidedly not the case for every Windows application. There were not two copies of Notepad or Solitaire; those are not extensible apps. Notepad did not offer a platform inviting third-party developers to add functionality packaged into DLLs meant for loading in-process.

Foreign architectures

This mismatch also explains the case of the “ghost” smart-card driver: those drivers are user-mode DLLs intended for in-process loading by the Windows cryptography API. Most applications interfacing with smart-cards only ship one version for the native architecture. For example there is exactly one copy of certreq for generating new certificate requests. On Windows ARM that is an ARM64 binary. It can not load DLLs written for the x64 architecture, even if those DLLs happen to present on the system.

That vindicates the installer: it was not hallucinating when it reported success. All of the necessary DLLs were indeed dropped in the right folder, which the installer was made to believe is the right place for shared library. Appropriate “registry” entries were created to inform Windows that a new smart-card driver was present and associated with cards of a particular model. But those changes happened in the simulated environment presented to x64 processes on Windows ARM. As far as native certreq ARM process is concerned, there is no evidence of this driver in the registry. (Manually creating the registry keys in the correct/non-redirected location will not solve the problem; it will only delay the inevitable failure point forward. The DLL those entries point to has the wrong architecture and will not load successfully.)

One could ask why the installer even proceeded in this situation: if “successful” completion of the install still results in an unusable setup guaranteed to fail at using the vendor hardware, why bother? But that assumes the installer is even aware that it is executing in a foreign architecture. Chances are when this installer was initially designed, the authors did not expect their product to be used on anything other than Intel x64 architecture. That is because binaries are by definition specific to one hardware platform and often a narrow range of operating system versions. The authors would have logically assumed there is no need to check for installation on ARM anymore than they had to check for RISC-V or PDP11: code execution would never reach that point if the condition being checked were true. It is redundant in the same way as checking if the system is currently experiencing a blue-screen.

The surprise is not why the installer incorrectly reported success. It is why the installer executed at all when invoked on a machine with completely unexpected hardware architecture where every instruction in the binary is being emulated to make it work. That is a testament to how well the ARM/x64 interoperability layer on Windows functions to sustain the illusion of a native Intel environment for emulated apps.

Post-script: limited workarounds

Interestingly MSFT did come up with a limited work-around for some of its core OS functionality, specifically the Windows shell, better known as “explorer.” The local predecessor of the more notorious Internet Explorer, this shell provides the GUI experience on Windows. Not surprisingly it has plenty of extensibility points for third-party developers to enhance or detract from the user-experience with additional functionality. For example, custom actions can be added to the right-click context menu such as upload this file to cloud drive, decompress this archive using some obscure format or scan for malware. Behind the scenes those additional functions are powered by COM components loaded in-process within explorer.

That model breaks when the shell is an x64 binary, while the COM object in question was compiled for x86. Unlike Internet Explorer where one can have a choice of two different versions to launch and even run them side-by-side, there can only be one Windows GUI active on the system. But this is where the use of COM standard also provides a general purpose solution. COM supports remote-procedure calls, “marshaling” data across process or even machine boundaries. By creating a 32-bit COM surrogate process, the shell can continue leveraging all of those 32-bit legacy extensions. They are now loaded in this separate 32-bit surrogate process and invoked cross-process from the hosting application. This trick is 100% transparent to the extension: as far as that COM object is concerned, it was loaded in-process by a 32-bit application exactly as the developers originally envisioned. (This is important because many extensions are not designed to deal with out-of-process calls.)

While that works for the shell, it does not work in general. Not every extensibility layer is designed with marshaling and remote-call capabilities in mind. Windows smart-card drivers are strictly based on a local API. While one could conceivably write a custom proxy to convert those into a remote call— indeed the ability forward smart-cards to a different machine over remote desktop proves this is possible— doing that is not as straightforward as opting into existing RPC capabilities of COM. Applications such as certreq do not have a magical interoperability layer to transparently use drivers written for a foreign architecture.

CP

** This story would become even more convoluted— and arguably an even better interview question— with additional updates to Internet Explorer. When IE8 introduced a multi-process architecture after being beaten to the punch by Google Chrome, its original design involved 64-bit “browser” hosting 32-bit “renderers” for individual tabs. Later versions introduced a an enhanced protected-mode that also used 64-bit renderers to leverage security improvements native to x64 binaries. This clunky and unsafe-by-default model persisted all the way through IE11. It was not until Edge that 32-bit browsers and native code extensions were finally deprecated.

Coinbase and the limits of DLP

In May, the world learned that Coinbase lost user data. Owing to disclosure requirements that apply to publicly-traded companies in the US, the company was compelled to issue a “confessional” SEC filing and associated blog-post dropping the news. Unnamed attackers had been extorting the company, threatening to release stolen private-information on customers obtained from an offshore vendor support vendor. Much as the announcement tried putting a brave face on the debacle and downplay the severity by pointing out that less than 1% of all customers were impacted, it was also notable for key omissions. For starters it turned out that one percent was not exactly random. Attackers had carefully targeted the most valuable customers: those with high-balance accounts, of greatest value to criminals interested in stealing cryptocurrency through social engineering.

While Coinbase was not upfront about what exactly went on, later reporting from Reuters and Fortune shed more light on the incident. It turned out the breach occurred in a decidedly low-tech fashion: Coinbase had outsourced its customer-support function to TaskUs, a business process outsourcing (BPO) company that operated support centers offshore with wages much lower than comparable US jobs. Some of those support representatives were bribed to funnel data over to the threat actor. These contractors did not have to “hack” anything any more than Edward Snowden had to breach anything at the NSA: by design, they were trusted insiders granted privileged access to Coinbase administrative systems for doing their daily jobs.

Granted, having access to customer data on your work machine is one thing. Shipping thousands of records from there to co-conspirators halfway around the world unnoticed is another. There is a slew of enterprise security products dedicated to making sure that does not happen. They are marketed under the catchy phrase DLP or “data-leak prevention.”

If we are being uncharitable, DLP threat-model can be summed up in one motto: “We catch the dumb ones.” These controls excel at stopping or at least detecting confidential information leaving the environment when the perpetrator makes no attempts to cover their tracks or lacks proper opsec skills despite best efforts. Example of rookie moves include:

  • Sending an email to your personal account from the corporate system, with a Word document attached containing the word “confidential”
  • Uploading the same document to Dropbox or Box (assuming those services are not used by the corporate IT environment, as would be the case for example when a company has settled on Google Workspace or Office365 for their cloud storage)
  • Creating a zip archive of an internal code repository and copying that to a removable USB drive.

Most DLP systems will sound the alarm when attackers are this inexperienced or brazen. But as soon as the slightest obfuscation or tradecraft is introduced, they can become surprisingly oblivious to what is happening.

Returning to the Coinbase incident: a natural question is whether TaskUs employed any DLP solutions, and if so, how the rogue insiders bypassed them so effectively that Coinbase remained oblivious as customer data went out the door for months. Not much has come to light about the exact IT environment of TaskUs. Were they running Windows or Macs? Did they have an old-school Active Directory setup or was the fleet managed through a more modern, cloud-centric setup such as Microsoft 365? There is good reason to expect the answers will be underwhelming. Customer support is outsourced overseas for one reason: reducing labor cost. It is unlikely that these shoestring-budget operations with their obsession on cost-cutting will be inclined to invest in fancy IT environments and robust security controls.

Yet it may not have mattered in the end. Some key details later emerged from an investigative piece on how the first handful of corrupt insiders were initially caught in January 2024— four months before Coinbase deigned to notify customers or investors about the extent of the problem. According to the Reuters article:

At least one part of the breach, publicly disclosed in a May 14 SEC filing, occurred when an India-based employee of the U.S. outsourcing firm TaskUs was caught taking photographs of her work computer with her personal phone, according to five former TaskUs employees.”

This is a stark reminder on the limitation of endpoint controls in general, not to mention the sheer futility of DLP technologies for protecting low-entropy information. TaskUs could have installed the kitchen sink of DLP solutions and not one of them would have made a difference for this specific attack vector. Equally misguided are calls for draconian restrictions on employee machines every time insider risks come up, as it must have for security teams in the aftermath of the Coinbase incident. It is possible to prevent screen-sharing and screenshots for specific URLs (Google Enterprise advertises controls for doing this in Chrome— assuming the IT department can reliably block all other browsers) or funnel all network traffic through a cloud proxy that only allows access to “known-good” websites. None of these prevent a disgruntled insider from using their phone to take a picture their desktop. For that matter, they can not stop a determined employee from memorizing short fragments of private information, such as the social-security number or address of a high-net-worth customer. This is much easier than trying to exfiltrate gigabytes of confidential documents or source code. Should customer support centers discriminate against candidates with good memorization skills?

To be clear, this is not an argument for throwing in the towel. There are standard precautions TaskUs could have taken given their threat model. Start with a policy against bringing personal devices into the workspace. This would at least have forced the malicious insiders to use company devices for exfiltration, giving DLP systems a fighting chance to catch them in case they stumbled. But even then, cameras are becoming ubiquitous in consumer electronics. Are employees not allowed to wear Meta Rayban glasses? For that matter, cameras are increasingly easy to conceal. Was that employee inspired to wear a three-piece suit to work today or is there a pinhole camera pointed at the screen hiding under that button?

In one sense, TaskUs and Coinbase were lucky. Customer service reps worked in a shared office space. They could witness and report on colleagues acting suspiciously. Consider how this scenario would have played out during the pandemic or for that matter in scenarios where employees are working remotely, with same level of access minus the deterrence factor of other people observing their actions.

CP

The mystery network interface: unexpected exfiltration paths

This is a story about accidentally stumbling on a trivial exfiltration path out of an otherwise locked-down environment. Our setting is a multi-national enterprise with garden-variety Windows-centric IT infrastructure with one modern twist: instead of physical workstations on desks or laptops, employees are issued virtual desktops. They connect to these Windows VMs to work from anywhere, getting a consistent experience whether they are physically situated in their own assigned office location, visiting one of the worldwide locations or from the comfort of their home— a lucky break that allowed for uninterrupted access during the pandemic.

Impact of virtualization

Virtualization makes some problems easier. It is an improvement over issuing employees laptops that leave the premises every night and can be used in the privacy of an employee residence without any supervision. Laptops walk out the door every night, can be stolen, stay offline for extended periods without security updates, connect to dubious public networks or interface with random hardware— printers, USB drives, docking stations, Bluetooth speakers— all of which create more novel ways to lose company data resident on that device. These risks are not insurmountable; there are well-understood mitigations for managing each one. For example, full-disk encryption can protect against offline recovery from disk in case of theft. But each one must be addressed by the defenders. Virtual desktops are immune from entire classes of attacks applicable to physical devices that can wander outside the trusted perimeter.

But virtualization can also introduce complications into other classic enterprise security challenges. Data leak prevention or DLP is one this particular firm greatly obsessed about. Most modern startups are far more concerned about external threat actors trying to sneak inside the gates and rampage through precious resources inside the perimeter. Businesses founded on intellectual property prioritize a different threat model: attackers already inside the perimeter moving confidential corporate data outside. Usually this is framed in the context of insider malfeasance: rogue employees jumping ship to a competitor trying to take some of the secret sauce with them. But under a more charitable interpretation, it can also be viewed as defense-in-depth against an external attacker who compromises the account of an otherwise honest insider, with the intention of rummaging through corporate IP. In all cases, defenders must focus on all possible exfiltration paths— avenues for communicating with the “outside world”— and implement controls on each channel.

Sure enough, the IT department spent an inordinate amount of time doing exactly that. For example, all connections to the Internet are funneled through a corporate proxy. When necessary that proxy executes a man-in-the-middle attack on TLS connections to view encrypted traffic. (No small irony that activity that would constitute criminal violation of US wiretap statutes in a public setting has become standard practice for IT departments that are possesses of a particular mindset around network security.) This setup affords both proactive defense and detection after the fact:

  1. Outright block connections to file-sharing sites such as Dropbox and Box to prevent employees from uploading company documents to unsanctioned locations. (Dreaded “shadow IT” problem.)
  2. Even for sites with permitted connection, log all history of connections, type of HTTP activity (GET vs POST vs PUT) including hash of the content exchanged. This allows identifying an employee after the fact if he/she goes on an upload spree to copy company IP from the internal environment to a cloud service.

Rearranging deck chairs

In other ways virtualization does not change the nature of risk but merely reshuffles it downstream, to the clients used for connecting to the machine where the original problem used to live.

This enterprise allowed connections from unmanaged personal devices. It goes without saying there will be little assurance about the security posture of a random employee device. (Despite the long history of VPN clients trying to encroach into device-management under the guise of “network health checks,” where connections are only permitted for clients devices “demonstrating” their compliance with corporate policies.) One way to solve this problem is by treating the remote client as untrusted: isolate content on the virtual desktop as much as possible from the client, effectively presenting a glorified remote GUI.

There is a certain irony here. Remote desktop access solutions have gotten better over time at supporting more integration with client-side hardware. For example over the years Microsoft RDP has added support to:

  • Share local drives with the remote machine
  • Use a locally attached printer to print
  • Allow local smart-cards to be used for logging into the remote system
  • Allow pasting from local clipboard to the remote machine, or vice verse by pasting content from the remote PC locally
  • Forward any local USB device such as webcam to the remote target
  • Forward local GPUs to the remote device via RemoteFX vGPU

These are supposed to be beneficial features: they improve productivity when using a remote desktop for computing. Yet they become trivial exfiltration vectors in the hands of a disgruntled employee trying to take corporate IP off their machine.

The mystery NIC

Fast forward to an employee connecting to their virtual desktop from home. Using the officially sanctioned VPN client and remote-desktop software anointed by the IT department, this person logs into their work PC as usual. Later on in the session, an unexpected OS notification appears regarding the discovery of an unknown network. That innocuous warning in fact signals a glaring oversight in exfiltration controls.

Peeking at “Network Connections” in Control Panel confirms the presence of a second network interface:

Network interfaces: the more, the merrier?

The appearance of the mystery NIC can be traced to an interaction between two routine actions:

  1. The employee connected their laptop to a docking station containing an Ethernet adapter. This is not an uncommon setup, since docking allows use of a larger secondary monitor and external keyboard/mouse for better ergonomics.
  2. Remote-desktop client was configured to forward newly connected USB devices to the remote server. This is also a common setup, to better single out devices that are intended for redirection by the explicit action of plugging them in after the session is created.
Microsoft RDP client settings for forwarding local devices. (Other remote-access clients have comparable features.)

The second point requires some qualifications. While arbitrary USB forwarding over RDP is clearly risky, it is necessary to forward some classes of devices. For instance, video conferencing requires a camera and microphone. Virtual desktops do not have any audio or video devices of their own. (Even if such emulated devices did exist and received synthetic A/V feeds, they would be useless for the purpose of projecting the real audio/video from the remote user.) That makes a blanket ban against all USB forwarding infeasible. Instead defenders are forced to carefully manage exceptions by device class.

It turns out in this case the configuration was too permissive: it allowed forwarding USB network adapters.

Free for all

On the remote side, once Windows detects the presence of an additional USB device, plug-and-play (once derided as plug-and-pray) works its magic:

  1. Device class is identified
  2. Appropriate device driver is loaded. There was an element of luck here in that the necessary driver was already present out-of-the-box on Windows, avoiding the need to search/download the driver via Windows Update. (This is still automatically done by Windows, for drivers that have passed WHQL certification.)
  3. Network adapter is initialized
  4. DHCP is used to acquire an IP address

Depending on group policy, some security controls continue to apply to this connection. For example the Windows firewall rules will still be in effect and can prevent accepting connections. But anything else not explicitly forbidden by policy will work. This is an important distinction. It turns out the reason many obvious exfiltration paths fail in the standard enterprise setup is an accident of network architecture, instead of deliberate endpoint controls. For instance, users can not connect to a random SMB share on the Internet because there is no direct route from the internal corporate network. By contrast mounting file-shares work just fine inside the trusted intranet environment; the difference is one of reachability. Similar observations apply to outbound SSH, SFTP, RDP and all other protocols except HTTP/HTTPS. (Because web access is critical to productivity, almost every enterprise fields dedicated forward proxies to sustain the illusion that every server on the Internet can be accessed on ports 80/443.) Most enterprises will not restrict connections using these protocols because of an implicit assumption that any host reachable on those ports is part of the trusted environment.

A secondary network interface changes that, opening another path for outbound connections. This one is no longer constrained by the intranet setup assumed by the IT department. Instead it depends on the network that Ethernet-to-USB adapter is attached to— one that is controlled by the adversary in this threat model. In the extreme case, it is wide open to connections from the internet. More realistically the virtual desktop will appear as yet another device on the LAN segment of a home network. In that case there will be some restrictions on inbound access but nothing preventing outbound connections.

Exfiltration possibilities are endless:

  1. Hard-copies of documents can be printed to a printer on the local network
  2. Network drives such as NAS units can be mounted as SMB shares, allowing easy drag-and-drop copy from virtual desktop.
  3. To stay under the radar, one can deploy another device on the local network to act as an SFTP server. On the virtual desktop side, an SFTP client such as putty or Windows’ own SSH client (standard on recent Win10/11 builds) can then upload files to that server. While activity involving file-shares and copying via Windows tends to be closely watched by resident EDR software, SFTP is unlikely to leave a similar audit trail.
  4. For those committed to GUI-based solutions, outbound RDP also works. One could deploy another Windows machine with remote access enabled on the home network, to act as the drop point for files. Then an RDP connection can be initiated from the virtual desktop, sharing the C:\ drive to the remote target. This makes the entire contents of the virtual desktop available to the unmanaged PC. While inbound RDP is disallowed from sharing drives, there are typically no such restrictions on outbound RDP— yet another artifact of the assumption that such connections can only work inside the safe confines of trusty intranet, where every possible destination is another managed enterprise asset.
  5. For a much simpler but noisier solution, vanilla cloud-storage sites (Box, Dropbox, …) will also accessible through the secondary interface. When connections are not going through the corporate proxy, rules designed to block file-sharing sites have no affect. Since most of these website offer file uploads through the web browser, no special software or dropping to a command line is required.
    • Caveat: It may take some finessing to get existing software on the remote desktop to use the second interface. While command line utilities such as curl will accept arguments to specify a particular interface used for initiating connections, browsers rarely expose that level of control.

These possibilities highlight a general point about the attackers’ advantage when it comes to preventing exfiltration from a highly connected environment. When a miss is as good as a mile, the fragility (futility?) of DLP solutions should ask customers to question whether this mitigation can amount to anything more than bureaucratic security theater.

CP