{"id":243,"date":"2026-09-24T09:30:33","date_gmt":"2026-09-24T09:30:33","guid":{"rendered":"https:\/\/getbitcoin.guide\/articles\/?p=243"},"modified":"2026-10-11T09:03:06","modified_gmt":"2026-10-11T09:03:06","slug":"keystone-hard-wallet","status":"publish","type":"post","link":"https:\/\/getbitcoin.guide\/articles\/keystone-hard-wallet\/","title":{"rendered":"Keystone Hard Wallet: What the Air Gap Does Not Stop"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>The Keystone hard wallet signs transactions by camera and QR code, so it never touches USB, Bluetooth or wifi. That removes the cable as an attack path. It does not remove the two risks that empty most wallets: a compromised companion app building the transaction, and a person approving an address without reading the device screen.<\/strong><\/p>\n\n\n\n<div class=\"msq-audio\" data-article=\"keystone-hard-wallet\" data-minutes=\"14\">\n<style>.msq-audio{margin:1.25em 0 1.75em;padding:16px 18px;background:#EEF3F8;border:1px solid #CBD8E6;border-radius:12px}\n.msq-audio-lead{margin:0 0 8px;font-size:.95em}.msq-audio audio{width:100%;margin:0 0 12px;display:block}\n.msq-toc-title{margin:0 0 6px;font-weight:700}.msq-toc ol{margin:0;padding:0;list-style:none}\n.msq-toc li{display:flex;gap:10px;align-items:center;padding:6px 6px;border-bottom:1px solid #CBD8E6;border-radius:8px}\n.msq-toc li:last-child{border-bottom:0}.msq-toc li.is-active{background:#fff}\n.msq-toc-play{flex:0 0 auto;width:30px;height:30px;border-radius:50%;border:0;background:#1F4E79;color:#fff;font:inherit;font-size:.72em;line-height:30px;padding:0;cursor:pointer}\n.msq-toc-play.is-playing{background:#B4531A}\n.msq-toc-time{flex:0 0 auto;min-width:3.1em;font-variant-numeric:tabular-nums;color:#4A5560;font-size:.9em}\n.msq-toc a{color:#1B1F24;text-decoration:none;line-height:1.35}.msq-toc li.is-active a{font-weight:700;color:#1F4E79}\n.msq-audio-note{margin:10px 0 0;font-size:.82em;color:#4A5560}\nh2.wp-block-heading[id]{scroll-margin-top:24px}\n.msq-hplay{display:inline-block;vertical-align:middle;width:26px;height:26px;margin:0 0 0 10px;border-radius:50%;border:0;background:#1F4E79;cursor:pointer;padding:0;position:relative;top:-2px}\n.msq-hplay::before{content:'\u25b6\ufe0e';display:block;color:#fff;font-size:11px;line-height:26px;text-align:center}\n.msq-hplay.is-playing{background:#B4531A}.msq-hplay.is-playing::before{content:'\u2016';font-size:13px;font-weight:700}\n.msq-bar{position:fixed;left:0;right:0;bottom:0;z-index:9000;display:flex;align-items:center;gap:10px;padding:8px 12px;padding-bottom:calc(8px + env(safe-area-inset-bottom));background:#FFFFFF;border-top:1px solid #CBD8E6;box-shadow:0 -4px 16px rgba(0,0,0,.08);font-size:.92em;color:#1B1F24;transition:transform .2s ease}\n.msq-bar.is-hidden{transform:translateY(130%)}\n.msq-bar-play{display:inline-flex;align-items:center;gap:8px;border:0;border-radius:999px;background:#1F4E79;color:#fff;font:inherit;font-weight:700;padding:8px 14px 8px 12px;cursor:pointer;white-space:nowrap}\n.msq-bar-play.is-playing{background:#B4531A}\n.msq-bar-icon::before{content:'\u25b6\ufe0e';font-size:12px}.msq-bar-play.is-playing .msq-bar-icon::before{content:'\u2016';font-size:14px;font-weight:700}\n.msq-bar-chapter{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.msq-bar-time{flex:0 0 auto;font-variant-numeric:tabular-nums;color:#4A5560;font-size:.9em}\n.msq-bar-rate,.msq-bar-close{flex:0 0 auto;border:1px solid #CBD8E6;background:#fff;color:#1B1F24;font:inherit;font-size:.85em;line-height:1;border-radius:8px;padding:7px 9px;cursor:pointer}\n.msq-bar-close::before{content:'\u2715'}\n.msq-bar.msq-bar-pill{left:auto;right:14px;bottom:14px;padding:6px;padding-bottom:6px;border:1px solid #CBD8E6;border-radius:999px;box-shadow:0 6px 20px rgba(0,0,0,.15)}\n.msq-bar.msq-bar-pill .msq-bar-chapter,.msq-bar.msq-bar-pill .msq-bar-time,.msq-bar.msq-bar-pill .msq-bar-rate{display:none}\nbody.msq-has-bar{padding-bottom:76px}\n@media (max-width:600px){.msq-bar-time{display:none}.msq-bar{gap:8px;padding-left:10px;padding-right:10px}}\n.msq-s.msq-now{background:#EEF3F8;box-shadow:0 2px 0 #1F4E79;border-radius:2px}\ntr.msq-now td,tr.msq-now th{background:#EEF3F8;box-shadow:inset 0 -2px 0 #1F4E79}\n@media (hover:hover){.msq-s,tr[data-i]{cursor:pointer}.msq-s:hover{background:#EEF3F8}}<\/style>\n<script type=\"application\/ld+json\">{\"@context\":\"https:\/\/schema.org\",\"@type\":\"AudioObject\",\"@id\":\"https:\/\/getbitcoin.guide\/articles\/keystone-hard-wallet\/#audio\",\"name\":\"Keystone Hard Wallet: What the Air Gap Does Not Stop, read aloud\",\"description\":\"Synthetic voice reading of the article, recorded 11 October 2026.\",\"contentUrl\":\"https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/10\/keystone-hard-wallet-audio-202610111432.mp3\",\"encodingFormat\":\"audio\/mpeg\",\"duration\":\"PT14M28S\",\"uploadDate\":\"2026-10-11\",\"inLanguage\":\"en-GB\",\"isAccessibleForFree\":true,\"mainEntityOfPage\":\"https:\/\/getbitcoin.guide\/articles\/keystone-hard-wallet\/\",\"hasPart\":[{\"@type\":\"Clip\",\"name\":\"Keystone Hard Wallet: What the Air Gap Does Not Stop\",\"startOffset\":0,\"endOffset\":56},{\"@type\":\"Clip\",\"name\":\"What does the air gap on a Keystone hard wallet actually remove?\",\"startOffset\":56,\"endOffset\":184,\"url\":\"https:\/\/getbitcoin.guide\/articles\/keystone-hard-wallet\/#what-does-the-air-gap-on-a-keystone-hard-wallet-actually-rem\"},{\"@type\":\"Clip\",\"name\":\"What does the air gap not remove?\",\"startOffset\":184,\"endOffset\":250,\"url\":\"https:\/\/getbitcoin.guide\/articles\/keystone-hard-wallet\/#what-does-the-air-gap-not-remove\"},{\"@type\":\"Clip\",\"name\":\"Is the Keystone hard wallet really open source?\",\"startOffset\":250,\"endOffset\":389,\"url\":\"https:\/\/getbitcoin.guide\/articles\/keystone-hard-wallet\/#is-the-keystone-hard-wallet-really-open-source\"},{\"@type\":\"Clip\",\"name\":\"What happened to Cobo Vault, and why does it matter?\",\"startOffset\":389,\"endOffset\":431,\"url\":\"https:\/\/getbitcoin.guide\/articles\/keystone-hard-wallet\/#what-happened-to-cobo-vault-and-why-does-it-matter\"},{\"@type\":\"Clip\",\"name\":\"What do people who have actually used one report?\",\"startOffset\":431,\"endOffset\":625,\"url\":\"https:\/\/getbitcoin.guide\/articles\/keystone-hard-wallet\/#what-do-people-who-have-actually-used-one-report\"},{\"@type\":\"Clip\",\"name\":\"How do you check a Keystone before you trust it with anything?\",\"startOffset\":625,\"endOffset\":794,\"url\":\"https:\/\/getbitcoin.guide\/articles\/keystone-hard-wallet\/#how-do-you-check-a-keystone-before-you-trust-it-with-anythin\"},{\"@type\":\"Clip\",\"name\":\"What has changed since this was first published?\",\"startOffset\":794,\"endOffset\":868,\"url\":\"https:\/\/getbitcoin.guide\/articles\/keystone-hard-wallet\/#what-has-changed-since-this-was-first-published\"}],\"contentSize\":\"6.1 MB\"}<\/script>\n<p class=\"msq-audio-lead\"><strong>Listen to this article<\/strong>, about 14 minutes. A synthetic voice reads the article and announces each section title as it begins; tables are read row by row and the questions at the end are left out.<\/p>\n<audio class=\"msq-audio-player\" controls preload=\"metadata\" src=\"https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/10\/keystone-hard-wallet-audio-202610111432.mp3\"><\/audio>\n<nav class=\"msq-toc\" aria-label=\"In this article\"><p class=\"msq-toc-title\">In this article<\/p>\n<ol>\n<li data-start=\"0.0\"><button type=\"button\" class=\"msq-toc-play\" data-start=\"0.0\" aria-label=\"Play from: Keystone Hard Wallet: What the Air Gap Does Not Stop\">&#x25B6;&#xFE0E;<\/button><span class=\"msq-toc-time\">0:00<\/span><a href=\"#top\">Keystone Hard Wallet: What the Air Gap Does Not Stop<\/a><\/li>\n<li data-start=\"55.82\"><button type=\"button\" class=\"msq-toc-play\" data-start=\"55.82\" aria-label=\"Play from: What does the air gap on a Keystone hard wallet actually remove?\">&#x25B6;&#xFE0E;<\/button><span class=\"msq-toc-time\">0:56<\/span><a href=\"#what-does-the-air-gap-on-a-keystone-hard-wallet-actually-rem\">What does the air gap on a Keystone hard wallet actually remove?<\/a><\/li>\n<li data-start=\"184.32\"><button type=\"button\" class=\"msq-toc-play\" data-start=\"184.32\" aria-label=\"Play from: What does the air gap not remove?\">&#x25B6;&#xFE0E;<\/button><span class=\"msq-toc-time\">3:04<\/span><a href=\"#what-does-the-air-gap-not-remove\">What does the air gap not remove?<\/a><\/li>\n<li data-start=\"249.98\"><button type=\"button\" class=\"msq-toc-play\" data-start=\"249.98\" aria-label=\"Play from: Is the Keystone hard wallet really open source?\">&#x25B6;&#xFE0E;<\/button><span class=\"msq-toc-time\">4:10<\/span><a href=\"#is-the-keystone-hard-wallet-really-open-source\">Is the Keystone hard wallet really open source?<\/a><\/li>\n<li data-start=\"389.24\"><button type=\"button\" class=\"msq-toc-play\" data-start=\"389.24\" aria-label=\"Play from: What happened to Cobo Vault, and why does it matter?\">&#x25B6;&#xFE0E;<\/button><span class=\"msq-toc-time\">6:29<\/span><a href=\"#what-happened-to-cobo-vault-and-why-does-it-matter\">What happened to Cobo Vault, and why does it matter?<\/a><\/li>\n<li data-start=\"431.26\"><button type=\"button\" class=\"msq-toc-play\" data-start=\"431.26\" aria-label=\"Play from: What do people who have actually used one report?\">&#x25B6;&#xFE0E;<\/button><span class=\"msq-toc-time\">7:11<\/span><a href=\"#what-do-people-who-have-actually-used-one-report\">What do people who have actually used one report?<\/a><\/li>\n<li data-start=\"624.88\"><button type=\"button\" class=\"msq-toc-play\" data-start=\"624.88\" aria-label=\"Play from: How do you check a Keystone before you trust it with anything?\">&#x25B6;&#xFE0E;<\/button><span class=\"msq-toc-time\">10:25<\/span><a href=\"#how-do-you-check-a-keystone-before-you-trust-it-with-anythin\">How do you check a Keystone before you trust it with anything?<\/a><\/li>\n<li data-start=\"794.22\"><button type=\"button\" class=\"msq-toc-play\" data-start=\"794.22\" aria-label=\"Play from: What has changed since this was first published?\">&#x25B6;&#xFE0E;<\/button><span class=\"msq-toc-time\">13:14<\/span><a href=\"#what-has-changed-since-this-was-first-published\">What has changed since this was first published?<\/a><\/li>\n<\/ol><\/nav>\n<p class=\"msq-audio-note\">Recorded 11 October 2026 from the article as published that day. Press a chapter to jump there; the highlighted line is what is playing. A play button sits beside every section heading, and once you scroll past this player a bar at the bottom of the screen keeps the controls in reach. Tap or click any sentence to hear the reading start from there.<\/p>\n<script>var MSQ_SENT = [[0.0,\"h\",\"keystonehardwalletwhatth\",42],[3.72,\"p\",\"thekeystonehardwalletsig\",89],[10.92,\"p\",\"thatremovesthecableasana\",33],[13.52,\"p\",\"itdoesnotremovethetworis\",149],[22.92,\"p\",\"onthispagethesevenstepqr\",225],[38.88,\"p\",\"searchthisdeviceandthefi\",114],[47.2,\"p\",\"noneofthemtakesthecentra\",35],[49.8,\"p\",\"sohereitistakenapartwith\",71],[55.82,\"h\",\"whatdoestheairgaponakeys\",52],[59.5,\"p\",\"keystonesownproductpagef\",190],[76.7,\"p\",\"thetransferclaimistheone\",83],[81.58,\"p\",\"apaymentleavesthewalleti\",79],[86.38,\"t\",\"1transactionisbuilt\",102],[97.46,\"t\",\"2apprendersananimatedqrc\",96],[108.86,\"t\",\"3keystonecamerareadsthec\",78],[117.62,\"t\",\"4screenshowsamountaddres\",89],[128.1,\"t\",\"5youapprovesecureelement\",84],[137.66,\"t\",\"6signedtransactionshowna\",94],[147.86,\"t\",\"7appscansitandbroadcasts\",96],[159.74,\"p\",\"stepstwothroughsixarethe\",41],[163.06,\"p\",\"nodrivernopairingnocable\",63],[169.66,\"p\",\"becauseaqrcodeisdataanys\",81],[176.9,\"p\",\"thesamereasoningappliest\",71],[184.32,\"h\",\"whatdoestheairgapnotremo\",26],[186.76,\"p\",\"stepsoneandsevensitonani\",92],[193.4,\"p\",\"theclassicattackgoesnowh\",162],[204.28,\"p\",\"threesecureelementswills\",66],[208.84,\"p\",\"keystoneknowsthisandsays\",69],[214.56,\"p\",\"theinstructiononreceivin\",230],[230.16,\"p\",\"thedevicescreenistheonly\",98],[237.88,\"p\",\"whichleavesthefailurenoh\",59],[242.52,\"p\",\"anairgapprotectsthekey\",22],[244.6,\"p\",\"ithasneveronceprotecteds\",70],[249.98,\"h\",\"isthekeystonehardwalletr\",39],[253.58,\"p\",\"mostlyandthegapisdocumen\",43],[257.26,\"p\",\"thekeystone3firmwarerepo\",210],[275.46,\"p\",\"thatisasmallerclosedsurf\",101],[282.78,\"p\",\"itisthesamedistinctionth\",80],[288.3,\"p\",\"betterstillthereisaverif\",45],[292.62,\"p\",\"therepositorysverifydocu\",159],[305.02,\"p\",\"fewwalletsatthispriceoff\",114],[312.74,\"p\",\"independentreviewexistsa\",59],[316.58,\"p\",\"leastauthoritysfinalaudi\",143],[328.86,\"p\",\"itfoundnocriticalissuesr\",72],[334.22,\"p\",\"itdidnotexaminethesecure\",68],[340.14,\"p\",\"anauditisonlyevercleanwi\",36],[342.86,\"p\",\"thesametestappliedtoacer\",121],[354.38,\"p\",\"twomorereviewsareonrecor\",25],[356.58,\"p\",\"apostonkeystonesownblogd\",199],[373.54,\"p\",\"injanuary2024keystoneann\",115],[382.98,\"p\",\"patchinganddisclosingist\",42],[385.54,\"p\",\"decliningtodescribethefl\",45],[389.24,\"h\",\"whathappenedtocobovaulta\",41],[392.36,\"p\",\"thedevicehasapreviousnam\",61],[396.6,\"p\",\"on1june2021lixinthenhead\",212],[411.96,\"p\",\"heleftwiththeoriginaltea\",113],[419.92,\"p\",\"sotheengineeringlineagei\",164],[431.26,\"h\",\"whatdopeoplewhohaveactua\",40],[434.22,\"p\",\"theaffiliatepagesrestate\",40],[437.02,\"p\",\"thepublicissuetrackerrec\",46],[440.26,\"p\",\"fiveaccountsalldatedandl\",88],[449.3,\"p\",\"theyaretestimonynotfindi\",27],[451.82,\"p\",\"therandompinpadisnotrand\",26],[454.42,\"p\",\"anissueopenedon1august20\",116],[464.66,\"p\",\"thefeatureexiststodefeat\",67],[469.18,\"p\",\"stillopenon11october2026\",24],[472.38,\"p\",\"aprojectcontributorrepli\",110],[479.34,\"p\",\"dicerollsshortoftheadver\",37],[482.06,\"p\",\"anissuefrom17june2026rep\",143],[495.86,\"p\",\"the12wordpathwascorrectl\",30],[498.78,\"p\",\"nowclosedandthe250firmwa\",93],[508.5,\"p\",\"ahangonthelastseedword\",22],[511.1,\"p\",\"issue2032opened27decembe\",175],[524.02,\"p\",\"stillopenon11october2026\",133],[536.18,\"p\",\"thisisthebuildfromsource\",65],[540.62,\"p\",\"largetransactionsthatwil\",32],[543.06,\"p\",\"anissuedated24september2\",104],[552.78,\"p\",\"nichebutareminderthatthe\",57],[556.46,\"p\",\"aflatbatteryaftertwoyear\",34],[558.54,\"p\",\"onkeystonestrustpilotpag\",184],[570.82,\"p\",\"anotherdescribedadevicea\",69],[576.14,\"p\",\"forrangethattrustpilotpr\",172],[591.06,\"p\",\"mostownersarehappy\",18],[592.7,\"p\",\"thesampleaboveisdelibera\",81],[598.46,\"p\",\"wheretheaccountsagreewit\",108],[605.46,\"p\",\"wheretheycutagainstitaba\",208],[618.82,\"p\",\"neithercostsyoucoinsifyo\",46],[622.22,\"p\",\"bothareworthknowingfirst\",24],[624.88,\"h\",\"howdoyoucheckakeystonebe\",50],[627.92,\"p\",\"ashortchecklistbuiltfrom\",71],[632.68,\"p\",\"buyfromthevendororanauth\",38],[635.48,\"p\",\"neveracceptadevicethatar\",79],[641.52,\"p\",\"thatistheoldesttheftinth\",83],[647.24,\"p\",\"letthedevicegeneratethes\",33],[649.72,\"p\",\"ifyouusethedicerolloptio\",96],[656.28,\"p\",\"verifythefirmwarebuildfr\",120],[666.8,\"p\",\"checkwhatiscurrent\",18],[668.4,\"p\",\"thereleasespagelistedver\",111],[679.0,\"p\",\"itwas310of17septemberwhe\",183],[693.84,\"p\",\"verifyeveryreceivingaddr\",112],[701.2,\"p\",\"chargeit\",8],[702.68,\"p\",\"ahardwarewalletwithabatt\",85],[709.08,\"t\",\"qrcodeandmicrosdtransfer\",163],[723.16,\"t\",\"threesecureelementchips\",153],[737.36,\"t\",\"opensource\",124],[750.12,\"t\",\"audited\",124],[763.36,\"t\",\"tamperresistant\",130],[776.48,\"p\",\"noneofthissaysthedevicei\",69],[781.44,\"p\",\"itisamapofwhattheairgapc\",90],[788.2,\"p\",\"ifthattradeisnottheoneyo\",89],[794.22,\"h\",\"whathaschangedsincethisw\",40],[796.7,\"p\",\"firmwaremovesandissuescl\",120],[805.34,\"p\",\"11october2026currentfirm\",116],[818.7,\"p\",\"itsnoteaddswalletmigrati\",73],[824.38,\"p\",\"11october2026therandompi\",61],[831.26,\"p\",\"aprojectcontributorwrote\",83],[838.02,\"p\",\"thispagepreviouslysaidth\",46],[841.14,\"p\",\"11october2026theseedimpo\",134],[854.22,\"p\",\"11october2026thecloseddi\",118]];\n(function(){\n  function init(){\n  var root = document.querySelector('.msq-audio'); if (!root) { return; }\n  var audio = root.querySelector('audio'), items = Array.prototype.slice.call(root.querySelectorAll('.msq-toc li'));\n  var starts = items.map(function(li){ return parseFloat(li.getAttribute('data-start')) || 0; });\n  var names = items.map(function(li){ return li.querySelector('a').textContent; });\n  var anchors = items.map(function(li){ var h = li.querySelector('a').getAttribute('href') || ''; return (h.charAt(0) === '#' && h !== '#top') ? document.getElementById(h.slice(1)) : null; });\n  var article = root.getAttribute('data-article') || location.pathname, minutes = root.getAttribute('data-minutes') || '';\n  var marks = {}, started = false, pausedAt = -1, closed = false, ended = false;\n  var RATES = [1, 1.25, 1.5], rate = 1;\n  try { var saved = parseFloat(localStorage.getItem('msq-audio-rate')); if (RATES.indexOf(saved) >= 0) { rate = saved; } } catch (e) {}\n  audio.playbackRate = rate;\n  function track(name, extra){ try { if (typeof gtag === 'function') { var p = { article: article }; for (var k in extra) { p[k] = extra[k]; } gtag('event', name, p); } } catch (e) {} }\n  function current(){ var t = audio.currentTime, idx = 0; for (var i = 0; starts.length > i; i += 1) { if (t + 0.25 >= starts[i]) { idx = i; } } return idx; }\n  function onScreen(){\n    var line = window.innerHeight \/ 3, idx = 0;\n    for (var i = 0; anchors.length > i; i += 1) { var el = anchors[i]; if (el && line >= el.getBoundingClientRect().top) { idx = i; } }\n    return idx;\n  }\n  function fmt(s){ s = Math.max(0, Math.round(s || 0)); var m = Math.floor(s \/ 60), r = s % 60; return m + ':' + (10 > r ? '0' : '') + r; }\n  function play(from, source){\n    if (from !== null) { audio.currentTime = from; }\n    var p = audio.play(); if (p && p.catch) { p.catch(function(){}); }\n    track(from === null ? 'audio_resume' : 'audio_chapter', { chapter: names[current()], start: Math.round(audio.currentTime), source: source });\n  }\n  var hbtns = anchors.map(function(el, i){\n    if (!el) { return null; }\n    var b = document.createElement('button'); b.type = 'button'; b.className = 'msq-hplay'; b.setAttribute('aria-label', 'Play this section: ' + names[i]);\n    b.addEventListener('click', function(){\n      if (!audio.paused && current() === i) { audio.pause(); track('audio_pause', { source: 'heading' }); return; }\n      play(starts[i], 'heading');\n    });\n    el.appendChild(b); return b;\n  });\n  var bar = document.createElement('div'); bar.className = 'msq-bar msq-bar-pill is-hidden'; bar.setAttribute('role', 'region'); bar.setAttribute('aria-label', 'Audio player');\n  var playBtn = document.createElement('button'); playBtn.type = 'button'; playBtn.className = 'msq-bar-play';\n  var icon = document.createElement('span'); icon.className = 'msq-bar-icon'; icon.setAttribute('aria-hidden', 'true');\n  var label = document.createElement('span'); label.className = 'msq-bar-label';\n  playBtn.appendChild(icon); playBtn.appendChild(label);\n  var chap = document.createElement('span'); chap.className = 'msq-bar-chapter';\n  var clock = document.createElement('span'); clock.className = 'msq-bar-time';\n  var rateBtn = document.createElement('button'); rateBtn.type = 'button'; rateBtn.className = 'msq-bar-rate'; rateBtn.setAttribute('aria-label', 'Playback speed');\n  var closeBtn = document.createElement('button'); closeBtn.type = 'button'; closeBtn.className = 'msq-bar-close'; closeBtn.setAttribute('aria-label', 'Close the audio bar');\n  bar.appendChild(playBtn); bar.appendChild(chap); bar.appendChild(clock); bar.appendChild(rateBtn); bar.appendChild(closeBtn);\n  document.body.appendChild(bar);\n  function showRate(){ rateBtn.textContent = (rate === 1 ? '1' : String(rate)) + 'x'; }\n  showRate();\n  rateBtn.addEventListener('click', function(){\n    rate = RATES[(RATES.indexOf(rate) + 1) % RATES.length]; audio.playbackRate = rate; showRate();\n    try { localStorage.setItem('msq-audio-rate', String(rate)); } catch (e) {}\n    track('audio_rate', { rate: rate });\n  });\n  closeBtn.addEventListener('click', function(){\n    closed = true; if (!audio.paused) { audio.pause(); } paint(); track('audio_bar_close', {});\n  });\n  function mode(){\n    if (!audio.paused) { return 'pause'; }\n    if (ended) { return 'again'; }\n    if (!started) { return 'listen'; }\n    return (pausedAt === onScreen()) ? 'resume' : 'section';\n  }\n  playBtn.addEventListener('click', function(){\n    var m = mode();\n    if (m === 'pause') { audio.pause(); track('audio_pause', { source: 'bar' }); return; }\n    if (m === 'again') { ended = false; play(0, 'bar'); return; }\n    if (m === 'resume') { play(null, 'bar'); return; }\n    play(starts[onScreen()], 'bar');\n  });\n  function paint(){\n    var idx = current(), playing = !audio.paused, m = mode();\n    items.forEach(function(li, i){\n      var on = (i === idx) && playing, b = li.querySelector('.msq-toc-play'), a = li.querySelector('a');\n      li.classList.toggle('is-active', on); b.classList.toggle('is-playing', on);\n      b.textContent = on ? '\u2016' : '\u25b6\ufe0e';\n      b.setAttribute('aria-label', (on ? 'Pause: ' : 'Play from: ') + a.textContent);\n    });\n    hbtns.forEach(function(b, i){ if (b) { var on = (i === idx) && playing; b.classList.toggle('is-playing', on); b.setAttribute('aria-label', (on ? 'Pause this section: ' : 'Play this section: ') + names[i]); } });\n    playBtn.classList.toggle('is-playing', playing);\n    label.textContent = m === 'pause' ? 'Pause' : m === 'again' ? 'Play again' : m === 'resume' ? 'Resume' : m === 'section' ? 'Play this section' : 'Listen, ' + minutes + ' min';\n    playBtn.setAttribute('aria-label', label.textContent);\n    chap.textContent = started ? names[(playing || m === 'resume') ? idx : onScreen()] : '';\n    clock.textContent = started ? fmt(audio.currentTime) + ' \/ ' + fmt(audio.duration) : '';\n    bar.classList.toggle('msq-bar-pill', !started);\n    var show = !closed && (started || 0 > root.getBoundingClientRect().bottom);\n    bar.classList.toggle('is-hidden', !show);\n    document.body.classList.toggle('msq-has-bar', show);\n  }\n  root.addEventListener('click', function(e){\n    var b = e.target.closest ? e.target.closest('.msq-toc-play') : null; if (!b) { return; }\n    var li = b.parentNode, s = parseFloat(b.getAttribute('data-start')) || 0;\n    if (!audio.paused && current() === items.indexOf(li)) { audio.pause(); track('audio_pause', { source: 'index' }); return; }\n    play(s, 'index');\n  });\n  audio.addEventListener('play', function(){ ended = false; closed = false; if (!started) { started = true; track('audio_play', { minutes: Math.round((audio.duration || 0) \/ 60) }); } paint(); });\n  audio.addEventListener('pause', function(){ pausedAt = current(); paint(); });\n  audio.addEventListener('timeupdate', function(){\n    paint();\n    if (audio.duration > 0) {\n      var pct = Math.floor(audio.currentTime \/ audio.duration * 100);\n      [25, 50, 75].forEach(function(m){ if (pct >= m && !marks[m]) { marks[m] = true; track('audio_progress', { percent: m }); } });\n    }\n  });\n  audio.addEventListener('ended', function(){ ended = true; track('audio_complete', {}); paint(); });\n  var ticking = false;\n  function onScroll(){ if (ticking) { return; } ticking = true; setTimeout(function(){ ticking = false; paint(); }, 80); }\n  window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll);\n  paint();\n  }\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }\n})();\n\n(function(){\n  function start(){\n    var root = document.querySelector('.msq-audio'), audio = root ? root.querySelector('audio') : null;\n    var map = (typeof MSQ_SENT !== 'undefined') ? MSQ_SENT : [];\n    if (!root || !audio || !map.length) { return; }\n    var scope = root.closest('main') || root.closest('article') || root.closest('.entry-content') || document.body;\n    var SKIP = '.msq-audio,.msq,.msq-tool,.msq-end,.msq-bar,script,style,noscript,figcaption,#rank-math-faq,.rank-math-block,nav,header,footer';\n    function norm(s){ return s.toLowerCase().replace(\/[^a-z0-9]+\/g, ''); }\n    var nodes = [], stream = '', walker = document.createTreeWalker(scope, NodeFilter.SHOW_TEXT, null), n;\n    while ((n = walker.nextNode())) {\n      var el = n.parentElement; if (!el || el.closest(SKIP)) { continue; }\n      var raw = n.nodeValue, keep = [], norms = '';\n      for (var i = 0; raw.length > i; i += 1) { var c = raw.charAt(i).toLowerCase(); if (\/[a-z0-9]\/.test(c)) { keep.push(i); norms += c; } }\n      if (!norms) { continue; }\n      nodes.push({ node: n, a: stream.length, b: stream.length + norms.length, keep: keep });\n      stream += norms;\n    }\n    var segs = [], cursor = 0, lastRow = null;\n    map.forEach(function(m, idx){\n      var kind = m[1], f = m[2], len = m[3];\n      if (kind === 't') {\n        var rows = scope.querySelectorAll('tr'), after = !lastRow;\n        for (var r = 0; rows.length > r; r += 1) {\n          var tr = rows[r];\n          if (!after) { if (tr === lastRow) { after = true; } continue; }\n          var cell = tr.querySelector('td,th');\n          if (cell && norm(cell.textContent).indexOf(f) === 0) { tr.setAttribute('data-i', idx); lastRow = tr; break; }\n        }\n        return;\n      }\n      var p = stream.indexOf(f, cursor); if (0 > p) { return; }\n      segs.push({ i: idx, a: p, b: Math.min(p + len, stream.length) }); cursor = p + len;\n    });\n    var si = 0;\n    nodes.forEach(function(nd){\n      var frag = document.createDocumentFragment(), raw = nd.node.nodeValue, rawPos = 0, any = false;\n      for (var k = si; segs.length > k; k += 1) {\n        var sg = segs[k]; if (sg.a >= nd.b) { break; } if (nd.a >= sg.b) { continue; }\n        var s = Math.max(sg.a, nd.a), e = Math.min(sg.b, nd.b);\n        var rs = nd.keep[s - nd.a], re2 = nd.keep[e - nd.a - 1] + 1;\n        if (rs > rawPos) { frag.appendChild(document.createTextNode(raw.slice(rawPos, rs))); }\n        var span = document.createElement('span'); span.className = 'msq-s'; span.setAttribute('data-i', sg.i); span.textContent = raw.slice(rs, re2);\n        frag.appendChild(span); rawPos = re2; any = true;\n        if (sg.b > nd.b) { break; }\n      }\n      while (segs.length > si && nd.b >= segs[si].b) { si += 1; }\n      if (!any) { return; }\n      if (raw.length > rawPos) { frag.appendChild(document.createTextNode(raw.slice(rawPos))); }\n      nd.node.parentNode.replaceChild(frag, nd.node);\n    });\n    var starts = map.map(function(m){ return m[0]; }), curIdx = -1, lastUser = 0, timer = null, autoUntil = 0, dragging = false;\n    function idxAt(t){ var lo = 0, hi = starts.length; while (hi > lo + 1) { var mid = (lo + hi) >> 1; if (t + 0.15 >= starts[mid]) { lo = mid; } else { hi = mid; } } return (t + 0.15 >= starts[0]) ? lo : -1; }\n    function setNow(i){\n      if (i === curIdx) { return; }\n      Array.prototype.forEach.call(scope.querySelectorAll('.msq-now'), function(el){ el.classList.remove('msq-now'); });\n      curIdx = i; if (0 > i) { return; }\n      var els = scope.querySelectorAll('[data-i=\"' + i + '\"]'); if (!els.length) { return; }\n      Array.prototype.forEach.call(els, function(el){ el.classList.add('msq-now'); });\n      var r = els[0].getBoundingClientRect(), now = Date.now();\n      if (!dragging && now > lastUser + 2500 && (80 > r.top || r.bottom > window.innerHeight - 140)) {\n        var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n        autoUntil = now + (reduce ? 400 : 1600);\n        els[0].scrollIntoView({ block: 'center', behavior: reduce ? 'auto' : 'smooth' });\n      }\n    }\n    function tick(){ if (!audio.paused) { setNow(idxAt(audio.currentTime)); } }\n    function userScrolled(){ lastUser = Date.now(); }\n    ['wheel', 'touchmove', 'keydown'].forEach(function(ev){ window.addEventListener(ev, userScrolled, { passive: true }); });\n    window.addEventListener('scroll', function(){ if (Date.now() > autoUntil) { userScrolled(); } }, { passive: true });\n    window.addEventListener('mousedown', function(e){ if (e.clientX >= document.documentElement.clientWidth) { dragging = true; userScrolled(); } }, { passive: true });\n    window.addEventListener('mouseup', function(){ if (dragging) { dragging = false; userScrolled(); } }, { passive: true });\n    audio.addEventListener('play', function(){ if (timer) { clearInterval(timer); } timer = setInterval(tick, 150); tick(); });\n    audio.addEventListener('pause', function(){ if (timer) { clearInterval(timer); timer = null; } });\n    scope.addEventListener('click', function(e){\n      if (e.target.closest('a, button, input, select, textarea, label, summary, .msq, .msq-tool, .msq-end, .msq-audio, .msq-bar')) { return; }\n      var sel = window.getSelection ? String(window.getSelection()) : '';\n      if (sel && sel.trim()) { return; }\n      var el = e.target.closest('[data-i]'); if (!el) { return; }\n      var i = parseInt(el.getAttribute('data-i'), 10); if (isNaN(i)) { return; }\n      if (!audio.paused && i === curIdx) { return; }\n      lastUser = Date.now();\n      audio.currentTime = starts[i];\n      var p = audio.play(); if (p && p.catch) { p.catch(function(){}); }\n      try { if (typeof gtag === 'function') { gtag('event', 'audio_chapter', { article: location.pathname, source: 'sentence', start: Math.round(starts[i]) }); } } catch (err) {}\n    });\n    audio.addEventListener('seeked', tick);\n    audio.addEventListener('ended', function(){ setNow(-1); });\n  }\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', start); } else { start(); }\n})();<\/script>\n<\/div>\n\n\n\n<p class=\"msq-hook wp-block-paragraph\">On this page: the seven step QR signing path and the three steps that still happen on your online machine, the one sentence in Keystone&#8217;s support pages that is the whole security model, what the audits actually covered and left out, and five dated issues from the public tracker.<\/p>\n\n\n\n<div class=\"msq\" id=\"ms-quiz\" data-slug=\"keystone-hard-wallet\" data-category=\"self custody and wallets\" data-list=\"1\">\n<style>.msq,.msq-hook,.msq-box,.msq-end,.msq-tool{--msq-accent:#1F4E79;--msq-accent-text:#FFFFFF;--msq-line:#CBD8E6;--msq-warn:#B4531A;--msq-muted:#4A5560;--msq-tint:#EEF3F8;--msq-base:#FFFFFF}\n.msq{margin:1.25em 0 1.75em}\n.msq-hook{border-left:3px solid var(--msq-accent);padding:6px 14px;color:var(--msq-muted);font-size:.97em}\n.msq-box{background:var(--msq-tint);border:1px solid var(--msq-line);border-radius:12px;padding:0}\n.msq-box>summary{cursor:pointer;list-style:none;padding:14px 18px;font-weight:700;color:var(--msq-accent)}\n.msq-box>summary::-webkit-details-marker{display:none}\n.msq-box>summary::before{content:\"+\";display:inline-block;width:1.1em;font-weight:800}\n.msq-box[open]>summary::before{content:\"\\00d7\"}\n.msq-body{padding:2px 18px 18px}\n.msq-intro{margin:0 0 12px;font-size:.95em;color:var(--msq-muted)}\n.msq-list{margin:0;padding:0;list-style:none}\n.msq-q{margin:0 0 18px;padding:0}\n.msq-question{font-weight:700;margin:0 0 8px}\n.msq-options{display:flex;flex-direction:column;gap:8px}\n.msq-opt{text-align:left;background:var(--msq-base);border:1px solid var(--msq-line);border-radius:8px;padding:10px 12px;font:inherit;font-size:.95em;color:inherit;cursor:pointer;line-height:1.35}\n.msq-opt:hover{border-color:var(--msq-accent)}\n.msq-opt[disabled]{cursor:default}\n.msq-opt.is-right{border-color:var(--msq-accent);background:var(--msq-line);font-weight:700}\n.msq-opt.is-wrong{border-color:var(--msq-warn);color:var(--msq-warn)}\n.msq-explain{margin:8px 0 0;font-size:.92em;padding:10px 12px;border-left:3px solid var(--msq-accent);background:var(--msq-base);border-radius:0 8px 8px 0}\n.msq-explain[hidden]{display:none}\n.msq-verdict{font-weight:700}\n.msq-result{margin-top:14px;padding:14px 16px;background:var(--msq-base);border:1px solid var(--msq-line);border-radius:10px}\n.msq-result[hidden]{display:none}\n.msq-result h3{margin:0 0 6px;font-size:1.1em}\n.msq-result p{margin:0 0 8px}\n.msq-jump{margin:0 0 8px;padding-left:1.2em}\n.msq-form{margin-top:10px;display:flex;flex-wrap:wrap;gap:8px;align-items:center}\n.msq-form input[type=email]{flex:1 1 220px;padding:10px 12px;border:1px solid var(--msq-muted);border-radius:8px;font:inherit;background:#fff}\n.msq-btn{background:var(--msq-accent);color:var(--msq-accent-text);border:0;border-radius:8px;padding:11px 18px;font:inherit;font-weight:700;cursor:pointer}\n.msq-btn:hover{filter:brightness(.92)}\n.msq-btn[disabled]{opacity:.7;cursor:default}\n.msq-no{font-size:.9em;color:var(--msq-muted);margin-left:4px}\n.msq-privacy{margin:6px 0 0;font-size:.82em;color:var(--msq-muted);flex-basis:100%}\n.msq-hp{position:absolute;left:-5000px;width:1px;height:1px;overflow:hidden}\n.msq-msg{margin:8px 0 0;font-size:.92em}\n.msq-end{margin:1.5em 0;padding:18px;border:1px solid var(--msq-accent);border-radius:12px;text-align:center;background:var(--msq-tint)}\n.msq-end p{margin:0 0 12px}\n.msq-end .msq-body{text-align:left;padding:16px 0 0}\n.msq-end .msq-start-test[hidden]{display:none}\n.msq-tool{margin:1.5em 0;padding:18px 20px;background:var(--msq-tint);border:1px solid var(--msq-line);border-radius:12px}\n.msq-tool h3{margin:0 0 6px;font-size:1.15em}\n.msq-tool p{margin:0 0 10px}\n.msq-tool .msq-note{font-size:.85em;color:var(--msq-muted);margin:10px 0 0}\n.msq-check label{display:flex;gap:10px;align-items:flex-start;padding:9px 0;border-bottom:1px solid var(--msq-line);cursor:pointer;line-height:1.4}\n.msq-check label:last-of-type{border-bottom:0}\n.msq-check input{margin-top:5px;flex:0 0 auto;width:18px;height:18px;accent-color:var(--msq-accent)}\n.msq-check-count{font-weight:700;margin:10px 0 0}\n.msq-verdict-box{margin:12px 0 0;padding:10px 14px;border-radius:8px;background:var(--msq-base);border-left:3px solid var(--msq-warn)}\n.msq-verdict-box[hidden]{display:none}\n.msq-calc{display:grid;grid-template-columns:1fr 1fr;gap:10px 16px}\n.msq-calc label{display:flex;flex-direction:column;gap:4px;font-size:.92em}\n.msq-calc input,.msq-calc select{padding:8px 10px;border:1px solid var(--msq-muted);border-radius:8px;font:inherit;background:#fff}\n.msq-calc-out{grid-column:1 \/ -1;margin-top:6px;padding:12px 14px;background:var(--msq-base);border-radius:8px;border:1px solid var(--msq-line)}\n.msq-calc-out strong{font-size:1.15em}\n.msq-choose label{display:block;padding:9px 12px;margin:0 0 8px;background:var(--msq-base);border:1px solid var(--msq-line);border-radius:8px;cursor:pointer}\n.msq-choose input{margin-right:8px;accent-color:var(--msq-accent)}\n.msq-choice-result{margin-top:10px;padding:12px 14px;background:var(--msq-base);border-left:3px solid var(--msq-accent);border-radius:0 8px 8px 0}\n.msq-choice-result[hidden]{display:none}\n@media (max-width:600px){.msq-calc{grid-template-columns:1fr}}\nh2.wp-block-heading[id]{scroll-margin-top:24px}<\/style>\n<noscript><style>.msq-explain{display:block !important}<\/style><\/noscript>\n<details class=\"msq-box\">\n<summary>Think you already know this? Five questions, one minute.<\/summary>\n<div class=\"msq-body\">\n<p class=\"msq-intro\">Every answer is on this page. Answer from what you know now; the page fills in the rest.<\/p>\n<ol class=\"msq-list\">\n<li class=\"msq-q\" data-q=\"1\" data-answer=\"b\" data-title=\"What does the air gap on a Keystone hard wallet actually remove?\" data-section=\"#what-does-the-air-gap-on-a-keystone-hard-wallet-actually-rem\">\n<p class=\"msq-question\">1. How does the Keystone 3 Pro move transaction data on and off the device?<\/p>\n<div class=\"msq-options\" role=\"group\" aria-label=\"Question 1 options\"><button type=\"button\" class=\"msq-opt\" data-opt=\"a\">A USB cable<\/button><button type=\"button\" class=\"msq-opt\" data-opt=\"b\">QR codes and microSD cards only<\/button><button type=\"button\" class=\"msq-opt\" data-opt=\"c\">Bluetooth pairing<\/button><\/div>\n<p class=\"msq-explain\" hidden><span class=\"msq-verdict\"><\/span>Per <a href=\"https:\/\/keyst.one\/shop\/products\/keystone-3-pro\" target=\"_blank\" rel=\"noopener\">Keystone&#8217;s product page<\/a>, which also lists three secure element chips, a 4 inch touchscreen and a $149 price; that transfer claim is the one that changes your threat model. <a class=\"msq-section\" href=\"#what-does-the-air-gap-on-a-keystone-hard-wallet-actually-rem\">Read the section<\/a><\/p>\n<\/li>\n<li class=\"msq-q\" data-q=\"2\" data-answer=\"b\" data-title=\"What does the air gap not remove?\" data-section=\"#what-does-the-air-gap-not-remove\">\n<p class=\"msq-question\">2. Where does the classic address swapping attack happen?<\/p>\n<div class=\"msq-options\" role=\"group\" aria-label=\"Question 2 options\"><button type=\"button\" class=\"msq-opt\" data-opt=\"a\">In the cable<\/button><button type=\"button\" class=\"msq-opt\" data-opt=\"b\">In the companion app on your online machine, before the QR code is ever drawn<\/button><button type=\"button\" class=\"msq-opt\" data-opt=\"c\">Inside the secure element<\/button><\/div>\n<p class=\"msq-explain\" hidden><span class=\"msq-verdict\"><\/span>Three secure elements will sign a theft as willingly as a rent payment, which is why <a href=\"https:\/\/support.keyst.one\/getting-started\/receiving-cryptocurrency\" target=\"_blank\" rel=\"noopener\">Keystone&#8217;s support page<\/a> says to verify receiving addresses on the device screen. <a class=\"msq-section\" href=\"#what-does-the-air-gap-not-remove\">Read the section<\/a><\/p>\n<\/li>\n<li class=\"msq-q\" data-q=\"3\" data-answer=\"b\" data-title=\"Is the Keystone hard wallet really open source?\" data-section=\"#is-the-keystone-hard-wallet-really-open-source\">\n<p class=\"msq-question\">3. What did the Least Authority audit dated 20 March 2025 cover?<\/p>\n<div class=\"msq-options\" role=\"group\" aria-label=\"Question 3 options\"><button type=\"button\" class=\"msq-opt\" data-opt=\"a\">The secure element hardware<\/button><button type=\"button\" class=\"msq-opt\" data-opt=\"b\">The QR protocol, the Zcash signing path and key generation in the firmware, finding no critical issues<\/button><button type=\"button\" class=\"msq-opt\" data-opt=\"c\">The battery and the camera<\/button><\/div>\n<p class=\"msq-explain\" hidden><span class=\"msq-verdict\"><\/span>Per <a href=\"https:\/\/leastauthority.com\/wp-content\/uploads\/2025\/03\/Least-Authority-ZCG-Keystone-Hardware-Wallet-Final-Audit-Report.pdf\" target=\"_blank\" rel=\"noopener\">the audit report<\/a>; it did not examine the secure element hardware and its scope was Zcash rather than Bitcoin, and an audit is only ever clean within its scope. <a class=\"msq-section\" href=\"#is-the-keystone-hard-wallet-really-open-source\">Read the section<\/a><\/p>\n<\/li>\n<li class=\"msq-q\" data-q=\"4\" data-answer=\"b\" data-title=\"What happened to Cobo Vault, and why does it matter?\" data-section=\"#what-happened-to-cobo-vault-and-why-does-it-matter\">\n<p class=\"msq-question\">4. What did Cobo do with the Cobo Vault in 2021?<\/p>\n<div class=\"msq-options\" role=\"group\" aria-label=\"Question 4 options\"><button type=\"button\" class=\"msq-opt\" data-opt=\"a\">Renamed it Keystone<\/button><button type=\"button\" class=\"msq-opt\" data-opt=\"b\">Moved it to minimum maintenance and stopped manufacturing, after which the hardware team left to start Keystone on the same firmware platform<\/button><button type=\"button\" class=\"msq-opt\" data-opt=\"c\">Sold it to a competitor<\/button><\/div>\n<p class=\"msq-explain\" hidden><span class=\"msq-verdict\"><\/span>Per <a href=\"https:\/\/blog.keyst.one\/leaving-cobo-to-continue-the-cobo-vault-legacy-29bb2f8f026e\" target=\"_blank\" rel=\"noopener\">the 1 June 2021 post<\/a>, which offered Cobo Vault owners a 50 percent upgrade coupon; a Cobo Vault on a resale site is a discontinued device. <a class=\"msq-section\" href=\"#what-happened-to-cobo-vault-and-why-does-it-matter\">Read the section<\/a><\/p>\n<\/li>\n<li class=\"msq-q\" data-q=\"5\" data-answer=\"a\" data-title=\"What do people who have actually used one report?\" data-section=\"#what-do-people-who-have-actually-used-one-report\">\n<p class=\"msq-question\">5. What did the issue opened on 1 August 2026 report about the random PIN pad?<\/p>\n<div class=\"msq-options\" role=\"group\" aria-label=\"Question 5 options\"><button type=\"button\" class=\"msq-opt\" data-opt=\"a\">That it uses a fixed compile time seed, so the layout is identical on every cold boot<\/button><button type=\"button\" class=\"msq-opt\" data-opt=\"b\">That it has too many digits<\/button><button type=\"button\" class=\"msq-opt\" data-opt=\"c\">That it drains the battery<\/button><\/div>\n<p class=\"msq-explain\" hidden><span class=\"msq-verdict\"><\/span>Per <a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\/issues\/2252\" target=\"_blank\" rel=\"noopener\">issue 2252 on the firmware repository<\/a>, still open with no maintainer reply when read; a feature meant to defeat shoulder surfing does not if the layout is predictable. <a class=\"msq-section\" href=\"#what-do-people-who-have-actually-used-one-report\">Read the section<\/a><\/p>\n<\/li>\n<\/ol>\n<div class=\"msq-result\" hidden><\/div>\n<\/div>\n<\/details>\n<script>(function(){\n  if (window.__msqInit) { return; }\n  window.__msqInit = true;\n  var root = document.getElementById('ms-quiz');\n  if (!root) { return; }\n  var meta = { slug: root.getAttribute('data-slug'), category: root.getAttribute('data-category'),\n               list: root.getAttribute('data-list') || '1' };\n  function qs(el, s){ return el.querySelector(s); }\n  function qsa(el, s){ return Array.prototype.slice.call(el.querySelectorAll(s)); }\n  function track(name, params){\n    try { if (typeof gtag === 'function') { var p = params || {}; p.article = meta.slug; gtag('event', name, p); } } catch (e) {}\n  }\n  function jumpList(missed){\n    if (!missed.length) { return ''; }\n    return '<ul class=\"msq-jump\">' + missed.map(function(q){\n      return '<li><a href=\"' + q.getAttribute('data-section') + '\">' + q.getAttribute('data-title') + '<\/a><\/li>';\n    }).join('') + '<\/ul>';\n  }\n  function emailForm(){\n    return '<div class=\"msq-sub\"><p><strong>Get the next one.<\/strong> We publish new articles on ' + meta.category\n      + ' most weeks and recheck this page on Sundays. Email me when a new article goes up or this page changes.<\/p>'\n      + '<form class=\"msq-form\" method=\"post\" action=\"\/mail\/form.php\" novalidate>'\n      + '<input type=\"hidden\" name=\"list\" value=\"' + meta.list + '\">'\n      + '<input type=\"hidden\" name=\"name\" value=\"\">'\n      + '<label class=\"msq-hp\" aria-hidden=\"true\">Leave this empty<input type=\"text\" name=\"website\" tabindex=\"-1\" autocomplete=\"off\"><\/label>'\n      + '<input type=\"email\" name=\"email\" placeholder=\"you@example.com\" required aria-label=\"Email address\" autocomplete=\"email\">'\n      + '<button type=\"submit\" class=\"msq-btn\">Email me the updates<\/button>'\n      + '<a href=\"#\" class=\"msq-no\">No thanks<\/a>'\n      + '<p class=\"msq-privacy\">We store your email and this page\\'s topic, nothing else. Unsubscribe any time.<\/p>'\n      + '<\/form><p class=\"msq-msg\" aria-live=\"polite\"><\/p><\/div>';\n  }\n  \/* The autoresponder always answers 200 with its own page. A \".msg.err\" box means the\n     address was rejected, \"You're subscribed\" means accepted, and a redirect only happens\n     after a successful subscribe. Same reading as the landing pages on the other sites. *\/\n  function sendForm(form){\n    return fetch(form.getAttribute('action'), { method: 'POST', body: new FormData(form), credentials: 'same-origin', redirect: 'manual' })\n      .then(function(res){\n        if (res.type === 'opaqueredirect') { return { status: 'ok' }; }\n        if (res.status === 404) { return { status: 'notlive' }; }\n        if (!res.ok) { throw new Error('HTTP ' + res.status); }\n        return res.text().then(function(t){\n          var doc = new DOMParser().parseFromString(t, 'text\/html');\n          var err = doc.querySelector('.msg.err');\n          if (err) {\n            var m = err.textContent.trim();\n            if (\/something went wrong\/i.test(m)) { throw new Error(m); }\n            return { status: 'rejected', message: m };\n          }\n          if (\/you.re subscribed\/i.test(doc.body.textContent)) { return { status: 'ok' }; }\n          return { status: 'unknown' };\n        });\n      });\n  }\n  function wireForm(sub){\n    var form = qs(sub, '.msq-form'), msg = qs(sub, '.msq-msg');\n    qs(form, '.msq-no').addEventListener('click', function(e){\n      e.preventDefault();\n      sub.innerHTML = '<p class=\"msq-msg\">No problem. The Sunday refresh keeps this page current either way.<\/p>';\n      track('quiz_email', { result: 'declined' });\n    });\n    form.addEventListener('submit', function(e){\n      e.preventDefault();\n      var input = qs(form, 'input[name=email]'), btn = qs(form, '.msq-btn');\n      var email = input.value.trim(); input.value = email;\n      if (!\/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(email)) { msg.textContent = 'That email does not look right.'; return; }\n      btn.disabled = true; btn.textContent = 'Sending';\n      function reset(){ btn.disabled = false; btn.textContent = 'Email me the updates'; }\n      sendForm(form).then(function(r){\n        if (r.status === 'ok' || r.status === 'unknown') {\n          sub.innerHTML = '<p class=\"msq-msg\"><strong>Done.<\/strong> We will email you when the next article on ' + meta.category\n            + ' goes up and when this page changes. If a confirmation email arrives, click it.<\/p>';\n          track('quiz_email', { result: r.status });\n          if (r.status === 'ok') { track('generate_lead', { method: 'quiz' }); }\n        } else if (r.status === 'notlive') {\n          msg.textContent = 'Sign up is not switched on yet for this site. Nothing was stored.'; reset();\n          track('quiz_email', { result: 'notlive' });\n        } else {\n          msg.textContent = r.message || 'Please check the email address and try again.'; reset();\n          track('quiz_email', { result: 'rejected' });\n        }\n      }).catch(function(){\n        msg.textContent = 'Could not reach the sign up service just now. Nothing was stored.'; reset();\n        track('quiz_email', { result: 'error' });\n      });\n    });\n  }\n  function finish(container, mode, score, total, missed){\n    var result = qs(container, '.msq-result');\n    track('quiz_complete', { mode: mode, score: score, total: total });\n    var h;\n    if (mode === 'pre') {\n      h = '<h3>You knew ' + score + ' of ' + total + ' before reading.<\/h3>';\n      h += (score === total) ? '<p>All of them. Read on anyway; the sections below carry the detail behind each answer.<\/p>'\n                             : '<p>The rest is below. Jump straight to what you missed:<\/p>' + jumpList(missed);\n      try { sessionStorage.setItem('msq-pre-' + meta.slug, String(score)); } catch (e) {}\n    } else {\n      var pre = null;\n      try { pre = sessionStorage.getItem('msq-pre-' + meta.slug); } catch (e) {}\n      h = '<h3>You got ' + score + ' of ' + total + '.<\/h3>';\n      if (pre !== null) { h += '<p>Before reading you had ' + pre + ' of ' + total + '.<\/p>'; }\n      if (missed.length) { h += '<p>Worth a second look:<\/p>' + jumpList(missed); }\n      h += emailForm();\n    }\n    result.innerHTML = h; result.hidden = false;\n    if (mode !== 'pre') { wireForm(qs(result, '.msq-sub')); }\n    result.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n  }\n  function setup(container, mode){\n    var qEls = qsa(container, '.msq-q'), answered = 0, score = 0, missed = [];\n    qEls.forEach(function(q){\n      var answer = q.getAttribute('data-answer'), opts = qsa(q, '.msq-opt'), explain = qs(q, '.msq-explain');\n      q.removeAttribute('data-done'); explain.hidden = true; qs(explain, '.msq-verdict').textContent = '';\n      opts.forEach(function(b){ b.disabled = false; b.classList.remove('is-right', 'is-wrong'); });\n      opts.forEach(function(b){\n        b.addEventListener('click', function(){\n          if (q.getAttribute('data-done')) { return; }\n          q.setAttribute('data-done', '1');\n          var ok = b.getAttribute('data-opt') === answer;\n          opts.forEach(function(o){ o.disabled = true; if (o.getAttribute('data-opt') === answer) { o.classList.add('is-right'); } });\n          if (ok) { score += 1; } else { b.classList.add('is-wrong'); missed.push(q); }\n          qs(explain, '.msq-verdict').textContent = ok ? 'Right. ' : 'Not quite. ';\n          explain.hidden = false;\n          answered += 1;\n          track('quiz_answer', { mode: mode, question: q.getAttribute('data-q'), correct: ok ? 1 : 0 });\n          if (answered === qEls.length) { finish(container, mode, score, qEls.length, missed); }\n        });\n      });\n    });\n  }\n  var box = qs(root, '.msq-box');\n  setup(root, 'pre');\n  if (box) { box.addEventListener('toggle', function(){ if (box.open) { track('quiz_open', { mode: 'pre' }); } }); }\n  \/* The end block sits far below this script, so it does not exist yet while this runs\n     during parsing. A delegated listener finds it at click time. *\/\n  document.addEventListener('click', function(e){\n    var startBtn = (e.target && e.target.closest) ? e.target.closest('.msq-start-test') : null;\n    if (!startBtn) { return; }\n    var end = startBtn.closest('.msq-end');\n    if (!end) { return; }\n    var mount = qs(end, '.msq-mount');\n    var clone = qs(root, '.msq-body').cloneNode(true);\n    var intro = qs(clone, '.msq-intro');\n    if (intro) { intro.textContent = 'The same five questions, now that you have read the page.'; }\n    var res = qs(clone, '.msq-result'); if (res) { res.hidden = true; res.innerHTML = ''; }\n    mount.innerHTML = ''; mount.appendChild(clone);\n    setup(mount, 'test');\n    startBtn.hidden = true;\n    track('quiz_open', { mode: 'test' });\n    mount.scrollIntoView({ behavior: 'smooth', block: 'start' });\n    var first = qs(mount, '.msq-opt'); if (first) { first.focus({ preventScroll: true }); }\n  });\n  \/* Shared tool behaviour: checklists remember their ticks on this device, and a chooser\n     shows the result for the option picked. Calculators carry their own small script. *\/\n  function initTools(){\n    qsa(document, '.msq-check').forEach(function(box){\n      var key = 'msq-check-' + meta.slug + '-' + (box.getAttribute('data-id') || 'x');\n      var boxes = qsa(box, 'input[type=checkbox]'), count = qs(box, '.msq-check-count');\n      var yes = qs(box, '.msq-verdict-yes'), no = qs(box, '.msq-verdict-no');\n      var saved = {};\n      try { saved = JSON.parse(localStorage.getItem(key) || '{}'); } catch (e) {}\n      boxes.forEach(function(cb, i){ if (saved[i]) { cb.checked = true; } });\n      function refresh(){\n        var n = boxes.filter(function(cb){ return cb.checked; }).length, state = {};\n        boxes.forEach(function(cb, i){ if (cb.checked) { state[i] = 1; } });\n        try { localStorage.setItem(key, JSON.stringify(state)); } catch (e) {}\n        if (count) { count.textContent = n + ' of ' + boxes.length + (box.getAttribute('data-verb') || ' done'); }\n        if (yes && no) { yes.hidden = n === 0; no.hidden = n !== 0; }\n      }\n      boxes.forEach(function(cb){ cb.addEventListener('change', function(){ refresh(); track('tool_check', { tool: box.getAttribute('data-id') }); }); });\n      refresh();\n    });\n    qsa(document, '.msq-choose').forEach(function(box){\n      var results = qsa(box, '.msq-choice-result');\n      qsa(box, 'input[type=radio]').forEach(function(r){\n        r.addEventListener('change', function(){\n          results.forEach(function(el){ el.hidden = el.getAttribute('data-for') !== r.value; });\n          track('tool_choose', { tool: box.getAttribute('data-id'), choice: r.value });\n        });\n      });\n    });\n  }\n  \/\/ read progress: how far down the article the reader has scrolled, fired once per quarter\n  (function(){\n    var art = root.closest('article') || root.parentNode, fired = {};\n    function check(){\n      var top = art.getBoundingClientRect().top + window.pageYOffset, h = art.offsetHeight || 1;\n      var seen = (window.pageYOffset + window.innerHeight - top) \/ h * 100;\n      [25, 50, 75, 100].forEach(function(m){ if (seen >= m && !fired[m]) { fired[m] = true; track('read_progress', { percent: m }); } });\n    }\n    window.addEventListener('scroll', check, { passive: true }); window.addEventListener('load', check);\n  })();\n  if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initTools); } else { initTools(); }\n})();<\/script>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Search this device and the first page hands you a marketplace listing, a wall of star ratings and a software wallet&#8217;s own integration guide. None of them takes the central claim apart. So here it is, taken apart, with the vendor&#8217;s documents quoted and the date they were read.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-does-the-air-gap-on-a-keystone-hard-wallet-actually-rem\">What does the air gap on a Keystone hard wallet actually remove?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/keyst.one\/shop\/products\/keystone-3-pro\" target=\"_blank\" rel=\"noopener\">Keystone&#8217;s own product page for the 3 Pro<\/a> says the device &#8220;employs QR codes and Micro SD cards for offline data transfer&#8221;, alongside three secure element chips, a 4 inch touchscreen, support for 5,500 plus assets and a listed price of $149. The transfer claim is the one worth tracing, because it is the only one that changes your threat model. A payment leaves the wallet in seven steps, and three of them happen on the machine in your pocket.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Step<\/th><th>Where it happens<\/th><th>What it trusts<\/th><\/tr><\/thead><tbody><tr><td>1. Transaction is built<\/td><td>Companion app, online<\/td><td>That the app has the right destination address<\/td><\/tr><tr><td>2. App renders an animated QR code<\/td><td>Phone or laptop screen<\/td><td>Nothing secret crosses here<\/td><\/tr><tr><td>3. Keystone camera reads the code<\/td><td>Device, offline<\/td><td>Its own parser<\/td><\/tr><tr><td>4. Screen shows amount, address, fee<\/td><td>Device, offline<\/td><td>Your eyes, and nothing else<\/td><\/tr><tr><td>5. You approve, secure element signs<\/td><td>Device, offline<\/td><td>That you read step 4<\/td><\/tr><tr><td>6. Signed transaction shown as a QR code<\/td><td>Device screen<\/td><td>Nothing secret crosses here<\/td><\/tr><tr><td>7. App scans it and broadcasts<\/td><td>Phone or laptop, online<\/td><td>Nothing, the signature covers it<\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">The QR signing path, traced against Keystone&#8217;s documentation, read on 24 September 2026.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Steps two through six are the air gap, and it is real. No driver, no pairing, no cable, so a malicious USB lead has nothing to attach to. Because a QR code is data any scanner can read, the channel is auditable in a way a USB packet never is. The same reasoning applies to every <a href=\"https:\/\/getbitcoin.guide\/articles\/ellipal-cold-wallet\/\" target=\"_blank\" rel=\"noopener\">QR based air gapped wallet, including the ELLIPAL<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1376\" height=\"768\" src=\"https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/close-up-verifying-keystone-hard-wallet-transactions.jpg\" alt=\"Hands holding a keystone hard wallet, checking the device screen before approving a payment.\" class=\"wp-image-241\" srcset=\"https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/close-up-verifying-keystone-hard-wallet-transactions.jpg 1376w, https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/close-up-verifying-keystone-hard-wallet-transactions-300x167.jpg 300w, https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/close-up-verifying-keystone-hard-wallet-transactions-1024x572.jpg 1024w, https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/close-up-verifying-keystone-hard-wallet-transactions-768x429.jpg 768w\" sizes=\"auto, (max-width: 1376px) 100vw, 1376px\" \/><figcaption class=\"wp-block-image__caption\">Users must still manually verify every transaction address on the device screen.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1600\" height=\"900\" src=\"https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/keystone-hard-wallet-chart.png\" alt=\"Timeline of the Keystone hard wallet QR signing path showing which steps happen online and which on the air gapped device\" class=\"wp-image-276\" srcset=\"https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/keystone-hard-wallet-chart.png 1600w, https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/keystone-hard-wallet-chart-300x169.png 300w, https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/keystone-hard-wallet-chart-1024x576.png 1024w, https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/keystone-hard-wallet-chart-768x432.png 768w, https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/keystone-hard-wallet-chart-1536x864.png 1536w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><figcaption class=\"wp-block-image__caption\">The air gap is real, and it covers the middle. The transaction is built and broadcast on an internet connected machine, which is where wallet draining malware lives, so the device screen is the only link malware cannot rewrite.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-does-the-air-gap-not-remove\">What does the air gap not remove?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Steps one and seven sit on an internet connected machine, which is exactly where wallet draining malware lives. The classic attack goes nowhere near the cable: it swaps the destination address in the companion app before the QR code is ever drawn, and the Keystone then faithfully signs a payment to a stranger. Three secure elements will sign a theft as willingly as they sign a rent payment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Keystone knows this and says so in its support pages rather than on the product page. The instruction on <a href=\"https:\/\/support.keyst.one\/getting-started\/receiving-cryptocurrency\" target=\"_blank\" rel=\"noopener\">receiving cryptocurrency<\/a> reads: &#8220;Please use addresses displayed on the Keystone device to verify receiving addresses, or scan the QR code format of the address displayed on the Keystone device when receiving.&#8221; That is the whole security model in one sentence. The device screen is the only link in the chain that malware on your laptop cannot rewrite, so the screen is what you read.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Which leaves the failure no hardware fixes: approving without looking. An air gap protects the key. It has never once protected someone who pressed confirm on a screen they did not read.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"is-the-keystone-hard-wallet-really-open-source\">Is the Keystone hard wallet really open source?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mostly, and the gap is documented rather than hidden. <a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\" target=\"_blank\" rel=\"noopener\">The Keystone 3 firmware repository<\/a> is published in Rust and C on FreeRTOS, and the README is straight about the exception: the MH1903 library ships precompiled rather than as source, for intellectual property reasons, with only its QR code component used. That is a smaller closed surface than most competitors admit to, and a larger one than &#8220;open source&#8221; implies on a product page. It is the same distinction that separates the devices in our guide to <a href=\"https:\/\/getbitcoin.guide\/articles\/crypto-wallet-open-source\/\" target=\"_blank\" rel=\"noopener\">open source crypto wallets<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Better still, there is a verification path you can walk. <a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\/blob\/master\/docs\/verify.md\" target=\"_blank\" rel=\"noopener\">The repository&#8217;s verify document<\/a> documents a Docker based reproducible build, after which you run a SHA256 checksum on the binary and compare it with the hash the device shows on its own screen. Few wallets at this price offer that, and almost no affiliate review mentions it, because it is hard to put an affiliate link on a Dockerfile.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Independent review exists and is narrower than the marketing implies. <a href=\"https:\/\/leastauthority.com\/wp-content\/uploads\/2025\/03\/Least-Authority-ZCG-Keystone-Hardware-Wallet-Final-Audit-Report.pdf\" target=\"_blank\" rel=\"noopener\">Least Authority&#8217;s final audit report for Zcash Community Grants, dated 20 March 2025<\/a> examined the QR code protocol, the Zcash signing path and key generation in the firmware. It found no critical issues, raised five suggestions and recorded all five as resolved. It did not examine the secure element hardware, and its scope was Zcash, not Bitcoin. An audit is only ever clean within its scope. The same test, applied to a certificate rather than an audit, is run on another QR signing device in <a href=\"https:\/\/getbitcoin.guide\/articles\/ngrave-zero-review\/\">what the NGRAVE ZERO EAL7 rating actually covers<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Two more reviews are on record. <a href=\"https:\/\/blog.keyst.one\/deep-dive-into-next-gen-hardware-wallet-crashing-keystone3-pro-audit-2729bc551d7b\" target=\"_blank\" rel=\"noopener\">A post on Keystone&#8217;s own blog dated 14 December 2023<\/a> reports a Keylabs audit finding &#8220;a high severity issue related to tamper response inadequacy, alongside two low Severity firmware issues, and three low severity hardware vulnerabilities&#8221;. In January 2024 Keystone announced that <a href=\"https:\/\/blog.keyst.one\/keystone-x-offside-labs-redefining-the-hardware-wallet-security-92fcb73dbf6c\" target=\"_blank\" rel=\"noopener\">Offside Labs had found a firmware vulnerability<\/a>, fixed in firmware 1.2.8, without saying what it was. Patching and disclosing is the behaviour you want. Declining to describe the flaw is the part to remember.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-happened-to-cobo-vault-and-why-does-it-matter\">What happened to Cobo Vault, and why does it matter?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The device has a previous name, and secondhand buyers keep running into it. On 1 June 2021 Lixin, then head of hardware at Cobo, <a href=\"https:\/\/blog.keyst.one\/leaving-cobo-to-continue-the-cobo-vault-legacy-29bb2f8f026e\" target=\"_blank\" rel=\"noopener\">published a post<\/a> explaining that Cobo had moved the Cobo Vault to minimum maintenance and stopped manufacturing, because a decentralised product no longer fitted a strategy built on centralised services. He left with the original team, started Keystone on the same firmware platform, and offered Cobo Vault owners a 50 percent upgrade coupon. So the engineering lineage is older than the brand, which is a point in its favour, and a Cobo Vault on a resale site is a discontinued device from a company that walked away from the category, which is not.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1376\" height=\"768\" src=\"https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/inspecting-keystone-hard-wallet-for-tampering.jpg\" alt=\"A man inspects a new keystone hard wallet at his desk for physical tampering.\" class=\"wp-image-242\" srcset=\"https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/inspecting-keystone-hard-wallet-for-tampering.jpg 1376w, https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/inspecting-keystone-hard-wallet-for-tampering-300x167.jpg 300w, https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/inspecting-keystone-hard-wallet-for-tampering-1024x572.jpg 1024w, https:\/\/getbitcoin.guide\/articles\/wp-content\/uploads\/2026\/09\/inspecting-keystone-hard-wallet-for-tampering-768x429.jpg 768w\" sizes=\"auto, (max-width: 1376px) 100vw, 1376px\" \/><figcaption class=\"wp-block-image__caption\">Carefully checking the hardware physical integrity before loading any private keys.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-do-people-who-have-actually-used-one-report\">What do people who have actually used one report?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The affiliate pages restate the specification. The public issue tracker records what actually breaks. Five accounts, all dated and linked, read on 24 September 2026 and their status rechecked on 11 October 2026. They are testimony, not findings.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>The random PIN pad is not random.<\/strong> <a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\/issues\/2252\" target=\"_blank\" rel=\"noopener\">An issue opened on 1 August 2026<\/a> reports that the shuffle uses a fixed compile time seed, so the keypad renders identically on every cold boot. The feature exists to defeat shoulder surfing, and a predictable layout does not. Still open on 11 October 2026. A project contributor replied on the day it was filed that a fix would be worked on, and no fix or pull request has been linked to it since.<\/li><li><strong>Dice rolls short of the advertised strength.<\/strong> <a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\/issues\/2182\" target=\"_blank\" rel=\"noopener\">An issue from 17 June 2026<\/a> reported that the firmware accepted 50 six sided dice rolls when creating a 24 word wallet, roughly 129 bits of entropy where the format implies 256. The 12 word path was correctly gated. Now closed, and the 2.5.0 firmware release of 29 June 2026 lists improved dice roll entropy validation in its notes.<\/li><li><strong>A hang on the last seed word.<\/strong> <a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\/issues\/2032\" target=\"_blank\" rel=\"noopener\">Issue 2032, opened 27 December 2025<\/a>, from a developer building the published firmware from source, describes the application hanging after the final word of a seed import, and notes recent posts going unanswered. Still open on 11 October 2026, though a contributor posted a root cause on 17 July 2026 and a pull request is linked to the issue, unmerged when this page was checked. This is the build from source path rather than a retail device, which narrows it.<\/li><li><strong>Large transactions that will not scan.<\/strong> <a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\/issues\/2294\" target=\"_blank\" rel=\"noopener\">An issue dated 24 September 2026<\/a> reports large Zcash transactions failing with an invalid QR code error above roughly 14 KiB. Niche, but a reminder that the QR channel has a ceiling a cable does not.<\/li><li><strong>A flat battery after two years in a drawer.<\/strong> On <a href=\"https:\/\/www.trustpilot.com\/review\/keyst.one\" target=\"_blank\" rel=\"noopener\">Keystone&#8217;s Trustpilot page<\/a> a reviewer reported a unit completely dead after two years of storage, which the company attributed to an over discharged lithium cell, with no prior warning that periodic charging was needed. Another described a device arriving with a dead camera and a 10 day wait for a refund.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">For range: that Trustpilot profile carried 732 reviews and a 4.6 score when it was read, 83 percent of them five stars and 6 percent one star, with the praise going to setup, build quality and support response times. Most owners are happy. The sample above is deliberately the unhappy tail, because that is the part nobody else publishes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Where the accounts agree with the official line: not one shows a key leaving the device, which is the claim the air gap actually makes. Where they cut against it: a battery powered device sold for long term storage that quietly dies in a drawer is a failure mode the marketing skips, and a security feature that ships deterministic is not something a specification sheet will ever tell you. Neither costs you coins if your <a href=\"https:\/\/getbitcoin.guide\/articles\/your-recovery-phrase\/\" target=\"_blank\" rel=\"noopener\">recovery phrase<\/a> is safe. Both are worth knowing first.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"how-do-you-check-a-keystone-before-you-trust-it-with-anythin\">How do you check a Keystone before you trust it with anything?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A short checklist, built from the vendor&#8217;s own documentation rather than from a review.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Buy from the vendor or an authorised reseller. Never accept a device that arrives already set up, and never use a seed phrase that came in the box. That is the oldest theft in this category, and it does not care how many secure elements the device has.<\/li><li>Let the device generate the seed itself. If you use the dice roll option, note the entropy issue above and keep rolling past the minimum the screen will accept.<\/li><li>Verify the firmware: build from source with the documented Docker image, run the SHA256 checksum, and compare it against the hash the device shows.<\/li><li>Check what is current. <a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\/releases\" target=\"_blank\" rel=\"noopener\">The releases page<\/a> listed version 3.1.2, dated 10 October 2026, as the most recent release when this article was checked on 11 October 2026. It was 3.1.0 of 17 September when this page was first written, which is the version the setup checklist below still names, and neither release note describes a security fix beyond the phrase enhanced security policies on 3.1.0.<\/li><li>Verify every receiving address on the device screen rather than in the companion app, exactly as the support documentation instructs.<\/li><li>Charge it. A hardware wallet with a battery is not a <a href=\"https:\/\/getbitcoin.guide\/articles\/what-is-a-cold-wallet\/\" target=\"_blank\" rel=\"noopener\">steel plate<\/a>, and a dead cell is a service call you did not plan for.<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Claim on the product page<\/th><th>What the public record shows<\/th><th>Source<\/th><\/tr><\/thead><tbody><tr><td>QR code and microSD transfer only<\/td><td>Confirmed. Removes USB and Bluetooth. Does not remove address substitution in the companion app.<\/td><td><a href=\"https:\/\/keyst.one\/shop\/products\/keystone-3-pro\" target=\"_blank\" rel=\"noopener\">product page<\/a> and <a href=\"https:\/\/support.keyst.one\/getting-started\/receiving-cryptocurrency\" target=\"_blank\" rel=\"noopener\">support docs<\/a><\/td><\/tr><tr><td>Three secure element chips<\/td><td>Stated in the firmware README. No independent audit of the secure element hardware found in public.<\/td><td><a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\" target=\"_blank\" rel=\"noopener\">firmware repository<\/a><\/td><\/tr><tr><td>Open source<\/td><td>Firmware published. The MH1903 library ships precompiled. Reproducible build documented.<\/td><td><a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\/blob\/master\/docs\/verify.md\" target=\"_blank\" rel=\"noopener\">verify.md<\/a><\/td><\/tr><tr><td>Audited<\/td><td>Zcash scope only, 20 March 2025, no critical issues, five suggestions all resolved.<\/td><td><a href=\"https:\/\/leastauthority.com\/wp-content\/uploads\/2025\/03\/Least-Authority-ZCG-Keystone-Hardware-Wallet-Final-Audit-Report.pdf\" target=\"_blank\" rel=\"noopener\">Least Authority report<\/a><\/td><\/tr><tr><td>Tamper resistant<\/td><td>A 2023 Keylabs audit reported one high severity tamper response issue.<\/td><td><a href=\"https:\/\/blog.keyst.one\/deep-dive-into-next-gen-hardware-wallet-crashing-keystone3-pro-audit-2729bc551d7b\" target=\"_blank\" rel=\"noopener\">Keystone blog, 14 December 2023<\/a><\/td><\/tr><\/tbody><\/table><figcaption class=\"wp-element-caption\">Specification claims set against public evidence, compiled 24 September 2026.<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">None of this says the device is good or bad, and none of it is a view on whether to own one. It is a map of what the air gap covers, which is the key, and what it leaves to you, which is everything on the screen. If that trade is not the one you want, the <a href=\"https:\/\/getbitcoin.guide\/articles\/safest-way-to-store-crypto\/\" target=\"_blank\" rel=\"noopener\">wider comparison of storage methods<\/a> runs through the alternatives.<\/p>\n\n\n\n<div class=\"msq-tool msq-check\" data-id=\"keystone-setup-check\" data-verb=\" done\">\n<h3>Before you trust a Keystone with anything<\/h3>\n<p>Built from the vendor&#8217;s own documentation rather than from a review. Tick each one once it is actually done.<\/p>\n<label><input type=\"checkbox\">Bought from the vendor or an authorised reseller, and refused any device that arrived set up or with a phrase in the box<\/label>\n<label><input type=\"checkbox\">Let the device generate the seed itself, and if using dice, kept rolling past the minimum the screen accepts<\/label>\n<label><input type=\"checkbox\">Verified the firmware: built from source with the documented Docker image and compared the SHA256 hash with the one on the device screen<\/label>\n<label><input type=\"checkbox\">Checked the releases page for the current version, 3.1.0 of 17 September when this page was checked<\/label>\n<label><input type=\"checkbox\">Verified every receiving address on the device screen, never only in the companion app<\/label>\n<label><input type=\"checkbox\">Charged it, and put a reminder in the calendar to charge it again<\/label>\n<p class=\"msq-check-count\"><\/p>\n<p class=\"msq-note\">A setup checklist from the vendor&#8217;s documentation, not a view on whether to own the device or what to keep on it. Ticks are saved on this device only.<\/p>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-has-changed-since-this-was-first-published\">What has changed since this was first published?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Firmware moves and issues close, so this page is rechecked on the weekly refresh and the entries below record what moved, when, and where it was read.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>11 October 2026: current firmware is 3.1.2, released 10 October 2026, up from 3.1.0 of 17 September when this page was written, per the <a href=\"https:\/\/github.com\/KeystoneHQ\/keystone3-firmware\/releases\" rel=\"nofollow noopener\" target=\"_blank\">releases page<\/a>. Its note adds wallet migration over USB for the Core extension and names no security fix.<\/li>\n\n\n<li>11 October 2026: the random PIN pad issue is still open, but it did get a reply. A project contributor wrote on 1 August 2026 that a fix would be worked on, and no fix is linked to it yet. This page previously said there had been no reply at all.<\/li>\n\n\n<li>11 October 2026: the seed import hang, issue 2032, is still open, and a contributor posted a root cause on 17 July 2026 with a pull request linked, unmerged when checked.<\/li>\n\n\n<li>11 October 2026: the closed dice roll issue now points at the 2.5.0 release of 29 June 2026, whose notes list improved dice roll entropy validation.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"frequently-asked-questions\">Frequently asked questions<\/h2>\n\n\n<div id=\"rank-math-faq\" class=\"rank-math-block\">\n<div class=\"rank-math-list \">\n<div id=\"faq-q-1\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Is a microSD transfer still air gapped?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>Yes in the sense that matters: the card carries data between two machines that are never electrically connected, with no network or driver involved. It is not identical to the QR path, though, because you cannot read a microSD card with your eyes. A QR code any scanner can decode. A card you have to trust.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-q-2\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">What happens if a Keystone hard wallet goes flat in storage?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>It is a battery powered device, and at least one Trustpilot reviewer reported a unit completely dead after two years untouched, which Keystone attributed to an over discharged lithium cell. Nothing is lost if your recovery phrase is intact, because the phrase holds your coins, not the device. It does mean a unit left in a safe needs charging occasionally.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-q-3\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Can Keystone recover your coins if the device is lost or destroyed?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>No, and that is by design. The company never holds your keys and cannot reconstruct them. Your recovery phrase is the only backup that exists, which is why where you keep it matters more than which device you bought. Anyone offering a recovery service for a self custody wallet is running a scam.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-q-4\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Is a secondhand Keystone hard wallet safe to set up?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>Only if you wipe it and generate a completely new seed phrase on the device yourself, and even then you are trusting firmware that a stranger controlled. A used unit arriving with a working wallet on it, or with a phrase written on a card, is a theft in progress. Never use a seed phrase you did not generate.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-q-5\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Does the fingerprint sensor replace the PIN code?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>It is a convenience layer on top, not a replacement. Keystone presents it as a faster way to unlock the device and approve transactions, with the PIN remaining the fallback. A fingerprint is also not a secret in the way a PIN is, since you leave copies of it on everything you touch.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-q-6\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Does three secure element chips mean three times the security?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>Not in any measurable sense. Multiple secure elements split duties and add redundancy, which is a reasonable design, but no independent audit of Keystone&#8217;s secure element hardware appears in the public record. The Least Authority review covered the Zcash software path, not the chips. Treat the count as an architecture note, not a security score.<\/p>\n\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n\n\n<div class=\"msq-end\" id=\"ms-quiz-end\">\n<p><strong>Finished the page?<\/strong> The same five questions from the top, to see what stuck.<\/p>\n<button type=\"button\" class=\"msq-btn msq-start-test\">Test Your Understanding of This Article<\/button>\n<div class=\"msq-mount\"><\/div>\n<\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><em>This article is educational and is not financial advice. Nothing here is a recommendation to buy, sell or hold anything. You are responsible for your own security decisions.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>What the Keystone hard wallet&#8217;s QR code air gap removes, what it leaves to you, and what five dated public accounts report about the device.<\/p>\n","protected":false},"author":1,"featured_media":240,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","rank_math_title":"Keystone Hard Wallet: What the Air Gap Does Not Stop","rank_math_description":"The Keystone hard wallet signs by QR code with no USB or Bluetooth. Here is what that air gap removes, what it leaves, and what owners report.","rank_math_focus_keyword":"keystone hard wallet","rank_math_canonical_url":"","rank_math_breadcrumb_title":"","rank_math_facebook_title":"","rank_math_facebook_description":"","rank_math_facebook_image":"","rank_math_twitter_title":"","rank_math_twitter_description":"","rank_math_twitter_image":"","rank_math_pillar_content":"","rank_math_robots":[],"rank_math_advanced_robots":[]},"categories":[2],"tags":[],"class_list":["post-243","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-wallets"],"_links":{"self":[{"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/posts\/243","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/comments?post=243"}],"version-history":[{"count":8,"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/posts\/243\/revisions"}],"predecessor-version":[{"id":557,"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/posts\/243\/revisions\/557"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/media\/240"}],"wp:attachment":[{"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/media?parent=243"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/categories?post=243"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/getbitcoin.guide\/articles\/wp-json\/wp\/v2\/tags?post=243"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}