324 lines
14 KiB
HTML
324 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html lang='en'>
|
|
<head>
|
|
|
|
<title>Handshake Re-Claim Inflation Bug: Full Disclosure</title>
|
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
|
|
<meta name="description" content="Handshake Re-Claim Inflation Bug: Full Disclosure" />
|
|
<meta property="og:title" content="Handshake Re-Claim Inflation Bug: Full Disclosure" />
|
|
<meta property="og:description" content="Handshake Re-Claim Inflation Bug: Full Disclosure" />
|
|
<meta property="og:url" content="https://handshake.org/notice/2020-04-01-Inflation-Bug-Disclosure.html" />
|
|
<meta property="og:image" content="https://www.handshake.org/images/landing/logo-dark.svg" />
|
|
|
|
<link rel="shortcut icon" href="/img/favicon/hns-favicon.ico" type="image/x-icon">
|
|
<link rel="stylesheet" type="text/css" href="/css/fonts/nitti.css" />
|
|
<link rel="stylesheet" type="text/css" href="/css/fonts/ibmplexmono.css" />
|
|
<link rel="stylesheet" type="text/css" href="/css/fonts/ibmplexsans.css" />
|
|
<link rel="stylesheet" type="text/css" href="/css/footer.css"/>
|
|
|
|
|
|
<link rel="stylesheet" type="text/css" href="/css/marketing.css" />
|
|
|
|
<style type="text/css">
|
|
.no-fouc {display: none;}
|
|
</style>
|
|
|
|
<script type="text/javascript">
|
|
document.documentElement.className = 'no-fouc';
|
|
</script>
|
|
|
|
</head>
|
|
|
|
<body class="light">
|
|
|
|
|
|
<header><div class="header-wrapper"><div class="inner-wrapper">
|
|
<nav id="navBar" class="no-js nav-bar">
|
|
|
|
|
|
<div id='nav-toggle' class="burgermenu" href="#">☰</div>
|
|
|
|
<div id='overlay'></div>
|
|
<div id="burgernav">
|
|
<ul>
|
|
|
|
<li><a href="https://handshake-org.github.io">Documentation</a></li>
|
|
<li><a href="/community">Community</a></li>
|
|
<li><a href="/faq">Faq</a></li>
|
|
|
|
|
|
</ul>
|
|
</div>
|
|
|
|
|
|
<a class="nav-logo" href="/">
|
|
<img class='logo logo-dark' src='/images/landing/logo-dark.svg' /><img class='logo logo-light' src='/images/landing/logo-light.svg' />
|
|
</a>
|
|
|
|
|
|
<div class="nav-right ">
|
|
<div class="nav-links "">
|
|
<ul>
|
|
|
|
|
|
<li><a href="https://handshake-org.github.io">Documentation</a></li>
|
|
<li><a href="/community">Community</a></li>
|
|
<li><a href="/faq">Faq</a></li>
|
|
|
|
|
|
|
|
</ul>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
</nav>
|
|
|
|
</div></div></header>
|
|
|
|
<div class="content">
|
|
<div class="wrapper">
|
|
|
|
|
|
|
|
<section class="notice default"><div class="section-wrapper"><div class='hero-no-split'>
|
|
<h1>Re-Claim Inflation Bug:<br>Full Disclosure</h1>
|
|
</div></div></section>
|
|
|
|
<section class="notice light"><div class="section-wrapper"><div>
|
|
<h2>BRIEF</h2>
|
|
<p>
|
|
Users' HNS coins, names, and HNS root zone data are not at risk.
|
|
A flaw was discovered in the Handshake protocol that could unintentionally increase
|
|
the total HNS coin supply beyond its designed limits. A user with a reserved name claim
|
|
could have have accidentally generated small amounts of extra HNS by modifying their wallet.
|
|
In the worst-case scenario, a malicious miner could generate nearly unlimited extra HNS in every block.
|
|
The bug was never exploited and is now fixed.
|
|
</p>
|
|
<p>
|
|
Miners and mining pools <i>MUST</i> upgrade their full nodes as soon as possible.<br>
|
|
All other users <i>SHOULD</i> upgrade as soon as possible:<br>
|
|
• <a href="/download">hsd v2.4.0</a><br>
|
|
• <a href="https://bobwallet.io">Bob Wallet v0.7.0 </a>
|
|
</p>
|
|
</div></div></section>
|
|
|
|
<section class="notice default timeline"><div class="section-wrapper"><div>
|
|
<h2>TIMELINE</h2>
|
|
<p>(All times UTC)</p>
|
|
<strong> March 24, 2021 16:00 </strong><br>
|
|
Matthew Zipkin discovers the protocol flaw and sends an encrypted email to
|
|
Christopher Jeffrey (JJ) with a description of the issue and a test demonstrating
|
|
an attack. JJ confirms the flaw and connects with Zipkin to discuss a solution.
|
|
Zipkin runs <a href="https://gist.github.com/pinheadmz/83b09668a2484f6c5a7b31f09a2e5054">this script</a> to confirm that the flaw has not yet been
|
|
exploited on the blockchain.<br><br>
|
|
<strong> March 24, 2021 18:00 </strong><br>
|
|
Joseph Poon is informed of the issue to help establish
|
|
a code fix and deployment plan. JJ starts writing patches for hsd and sharing
|
|
them with Zipkin as the solution and deployment plan evolve.<br><br>
|
|
<strong> March 25, 2021 07:00 </strong><br>
|
|
JJ shares a new version of the patch based on discussion with the team,
|
|
including covert soft-fork signaling suggested by Zipkin.<br><br>
|
|
<strong> March 25, 2021 18:00 </strong><br>
|
|
F2Pool is contacted and informed of the issue.<br><br>
|
|
<strong> March 28, 2021 01:00 </strong><br>
|
|
JJ sends Zipkin final patch for review and testing.
|
|
Extra chain-reorganization protection is included in case of a chain split during deployment.<br><br>
|
|
<strong> March 28, 2021 03:00 </strong><br>
|
|
F2Pool and Poolin are contacted, sent the patch and begin upgrading.
|
|
Covert signals appear in blocks 61038 and 61039. DX Pool is contacted.<br><br>
|
|
<strong> March 29, 2021 08:00 </strong><br>
|
|
DX Pool upgrades. Covert signaling approaches 70%.<br><br>
|
|
<strong> March 29, 2021 23:00 </strong><br>
|
|
Urkel Pool contacted.<br><br>
|
|
<strong> March 30, 2021 13:00 </strong><br>
|
|
ViaBTC and Huobi contacted. Patch sent to Urkel Pool and ViaBTC, both upgrade.<br><br>
|
|
<strong> March 31, 2021 00:00 </strong><br>
|
|
Signaling approaches 80%. Bob Wallet is contacted.<br><br>
|
|
<strong> March 31, 2021 02:00 </strong><br>
|
|
Huobi gets the patch and upgrades.<br><br>
|
|
<strong> April 1, 2021 22:00 </strong><br>
|
|
Signaling approaches 90%. Namebase and Bob Wallet are contacted again and alerted to the deployment plan.<br><br>
|
|
<strong> April 2, 2021 16:00 </strong><br>
|
|
Patch is released as hsd v2.4.0 along with Bob Wallet v0.7.0, full disclosure is published.<br><br>
|
|
</div></div></section>
|
|
|
|
<section class="notice light"><div class="section-wrapper"><div>
|
|
<h2>DETAILS</h2>
|
|
<p>
|
|
The Handshake protocol allows owners of certain domain names in the legacy DNS to claim
|
|
their name on the Handshake blockchain. The claim requires a DNSSEC proof and is
|
|
submitted to the network in a special type of transaction. This means malicious
|
|
activity in the legacy DNS could potentially disrupt the Handshake system. In
|
|
<a href="https://github.com/handshake-org/hsd/issues/103">this issue</a>, JJ
|
|
discusses a solution to the "what if GoDaddy gets hacked" problem. The solution
|
|
adds a 30-day lockout to name claims before they can be registered, and
|
|
enables legacy name owners to re-submit a claim to the network any time before
|
|
they <code>REGISTER</code>. These claims generate new HNS coins as a reward,
|
|
but only the final <code>CLAIM</code> can actually be spent (by the <code>REGISTER</code>
|
|
transaction) keeping the money supply intact. However, the miner fees paid
|
|
by each <code>CLAIM</code> were not protected in the same way. This means that
|
|
if a user re-submitted a <code>CLAIM</code>, they would pay an additional miner
|
|
fee that would not be accounted for by the protocol design, inflating the money supply.
|
|
Since fees are chosen by the user who submits the <code>CLAIM</code>, the flaw
|
|
could be exploited intentionally to generate unlimited HNS.
|
|
</p>
|
|
<p>
|
|
Luckily, the hsd wallet does not currently allow users to re-claim (but it should, and it will soon).
|
|
However, a curious user might be able to edit the wallet code and force it to submit a new <code>CLAIM</code>
|
|
to the network, accidentally exploiting the bug. If, for example, a user lost the keys they used to
|
|
generate their initial <code>CLAIM</code> (meaning the actual <code>TXT</code> record used in the proof)
|
|
they may try to generate a new one with another wallet, and submit a re-claim. Note that the extra-generated coins
|
|
are given to a miner as a fee and are not spendable by the claimer. A malicious miner
|
|
could have collaborated with a legacy name holder or obtained a reserved legacy name, and submitted
|
|
a new <code>CLAIM</code> with each block they mine, potentially paying themselves 100%
|
|
of the name's reward as a fee.
|
|
</p>
|
|
<p>
|
|
This flaw is not just an implementation bug that could be fixed with a software patch.
|
|
It is a problem with the design of the Handshake protocol and so it affects every
|
|
user and all hsd full nodes. The only way to fix this kind of issue is with a soft fork,
|
|
which adds new rules to the protocol and is enforced by miners. Specifically,
|
|
the miners run new code that prevents the re-claims from inflating the money supply.
|
|
Due to the severity of the flaw and the low difficulty of execution, the issue had
|
|
to be disclosed to limited parties, and very carefully. The team contacted F2Pool and
|
|
Poolin initially because together they make up over 50% of the network hashrate.
|
|
Once 51% of the hashrate was patched there existed a potential outcome where a minority
|
|
miner might unknowingly mine a block that is invalid under the new rules. That block
|
|
would be forked off the chain by the majority miners. This is why as soon as 51%
|
|
of the hashrate was upgraded, the minority mining pools were informed as quickly as possible.
|
|
Finally, the patch had to be deployed to all users who run full nodes.
|
|
This process reflected the priorities and trade-offs for deployment:<br>
|
|
1. Protect users from inflation attacks (upgrade a majority of the hashrate).<br>
|
|
2. Protect miners from each other (upgrade the remainder of the hashrate).<br>
|
|
3. Protect users from the miners (deploy the patch as widely as possible).<br>
|
|
</p>
|
|
<p>
|
|
Normally soft forks are widely advertised and deployment is obvious,
|
|
but this was a sensitive matter: the flaw could not be disclosed until the new
|
|
protocol rules were in place and enforced by as much hashrate as possible.
|
|
Therefore, the patch included a covert signaling mechanism so the team could monitor its
|
|
deployment. The code inserted two marker bytes (<code>0xf0ba</code>)
|
|
into the second witness item in each coinbase transaction (a field normally filled
|
|
with 8 random bytes). When the deployment
|
|
reached 90% the team decided it was safe enough to disclose the patch publicly.
|
|
</p>
|
|
</div></div></section>
|
|
|
|
<section class="notice default"><div class="section-wrapper"><div>
|
|
<h2>NEW PROTOCOL RULES</h2>
|
|
<p>
|
|
A <code>CLAIM</code> must commit to a mainnet block hash. By default, all
|
|
claims commit to block #1. The existing rules already require that subsequent
|
|
re-claims commit to higher block heights. This makes it easy to determine in
|
|
the software when a claim is being re-submitted (<code>commitHeight > 1</code>).
|
|
The following new rules are enforced by the soft-fork code:
|
|
</p>
|
|
<p>
|
|
• An initial <code>CLAIM</code> MUST commit to block #1.<br>
|
|
• An initial <code>CLAIM</code> MUST pay a fee less than 1,000 HNS.<br>
|
|
• A re-claim MUST pay the exact same fee as the initial <code>CLAIM</code>.<br>
|
|
• The fees from any re-claim MUST NOT be collected by the miner:
|
|
they are "burned" or, more accurately, already exist in a previous block.<br>
|
|
• A re-claim can not be mined until 288 blocks have passed since the last <code>CLAIM</code> or re-claim.<br>
|
|
</p>
|
|
|
|
</div></div></section>
|
|
|
|
|
|
<footer id='footer'>
|
|
<!-- the onboarding pages and dashboard use the small footer -->
|
|
|
|
<div class='footer-wrap'>
|
|
<nav>
|
|
<div class='header'>
|
|
<h3>Handshake</h3>
|
|
<span><img class='footer-caret-down' src='/img/footer/down-caret.svg' alt='Toggle expanded menu on mobile'/></span>
|
|
<span><img class='footer-caret-up hide' src='/img/footer/up-caret.svg' alt='Toggle expanded menu on mobile'/></span>
|
|
</div>
|
|
<div class='links'>
|
|
<a href='/'>Home</a>
|
|
<a href='/community'>Community</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<nav>
|
|
<div class='header'>
|
|
<h3>Learn</h3>
|
|
<span><img class='footer-caret-down' src='/img/footer/down-caret.svg' alt='Toggle expanded menu on mobile'/></span>
|
|
<span><img class='footer-caret-up hide' src='/img/footer/up-caret.svg' alt='Toggle expanded menu on mobile'/></span>
|
|
</div>
|
|
<div class='links'>
|
|
<a href='/faq'>FAQ</a>
|
|
<a href='/files/handshake.txt'>Design Notes</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<nav>
|
|
<div class='header'>
|
|
<h3>Develop</h3>
|
|
<span><img class='footer-caret-down' src='/img/footer/down-caret.svg' alt='Toggle expanded menu on mobile'/></span>
|
|
<span><img class='footer-caret-up hide' src='/img/footer/up-caret.svg' alt='Toggle expanded menu on mobile'/></span>
|
|
</div>
|
|
<div class='links'>
|
|
<a href='https://handshake-org.github.io'>Documentation</a>
|
|
<a href='https://github.com/handshake-org/hsd'>Run a full node</a>
|
|
<a href='https://github.com/handshake-org/hnsd'>Install an SPV resolver</a>
|
|
<a href='https://handshake-org.github.io/guides/auctions.html'>Auction system guide</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Keeps things in line -->
|
|
<nav style="display:none;">
|
|
</nav>
|
|
</div><!-- close center-wrap -->
|
|
|
|
|
|
|
|
|
|
<div class='footer-wrap bottom-wrap'>
|
|
<a href='/'>
|
|
Home
|
|
</a>
|
|
<a href='/terms-of-use'>
|
|
Terms of Use
|
|
</a>
|
|
<a href='/privacy-policy'>
|
|
Privacy Policy
|
|
</a>
|
|
<a href='/trademark-disclaimer'>
|
|
Trademark Disclaimer
|
|
</a>
|
|
|
|
<nav class='social-icons-small-footer'>
|
|
<a href='https://github.com/handshake-org/'>
|
|
<img src='/img/footer/github.svg' alt='GitHub logo'/>
|
|
</a>
|
|
<a href='https://twitter.com/hns'>
|
|
<img src='/img/footer/twitter.svg' alt='Twitter logo'/>
|
|
</a>
|
|
<a href='https://reddit.com/r/handshake'>
|
|
<img src='/img/footer/reddit.svg' alt='Reddit logo'/>
|
|
</a>
|
|
</nav>
|
|
</div>
|
|
|
|
|
|
</footer>
|
|
|
|
<script src='/js/footer.js'></script>
|
|
<script src='/js/nav.js'></script>
|
|
<script>
|
|
window.addEventListener("load", function(e) {
|
|
document.documentElement.className = '';
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|