-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrss.xml
More file actions
1255 lines (947 loc) · 95.8 KB
/
Copy pathrss.xml
File metadata and controls
1255 lines (947 loc) · 95.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://bitfinding.com/rss.xml" rel="self" type="application/atom+xml" /><link href="https://bitfinding.com/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-09-07T16:43:09-03:00</updated><id>https://bitfinding.com/rss.xml</id><title type="html">Bitfinding</title><subtitle>Bitfinding builds advanced security for decentralized systems with a focus on integrity, resilience, and trust.</subtitle><entry><title type="html">Signature overflow attacks on Ledger</title><link href="https://bitfinding.com/blog/signature-overflow-attacks-on-ledger/" rel="alternate" type="text/html" title="Signature overflow attacks on Ledger" /><published>2026-09-07T00:00:00-03:00</published><updated>2026-09-07T00:00:00-03:00</updated><id>https://bitfinding.com/blog/signature-overflow-attacks-on-ledger</id><content type="html" xml:base="https://bitfinding.com/blog/signature-overflow-attacks-on-ledger/"><![CDATA[<p>A Ledger Clear Signing bug let an affected device display one action while
its signature authorized 257. A signer could approve what looked like a routine
transaction without seeing the other actions covered by the signature.</p>
<p>We tested Safe, Aave, and Morpho Clear Signing flows. This essay examines the
finding and its implications for hardware-wallet trust. The
<a href="https://github.com/BitFinding/publications/blob/main/LEDGER_CLEAR_SIGNING_BYPASS.md">security advisory</a>
documents affected versions, mitigations, and coordinated disclosure.</p>
<blockquote>
<p><strong>Remediation status:</strong> Ledger Ethereum app <code class="language-plaintext highlighter-rouge">1.22.3</code> rejects the demonstrated
flows. Users should update the Ethereum app separately from their device
firmware. See the advisory for the affected-version matrix and verification
guidance.</p>
</blockquote>
<p><img src="/assets/images/blog/signature-overflow-attacks-on-ledger/hero.png" alt="Signature overflow attacks on Ledger: one call displayed, 257 calls signed" /></p>
<h2 id="1-the-threat-model">1. The Threat Model</h2>
<p>Ledger’s security premise is sound: the computer and transaction interface may
be compromised. Its
<a href="https://donjon.ledger.com/threat-model/device-secure-display-and-inputs/">secure-display threat model</a>
therefore requires the device to preserve <strong>What You See Is What You Sign</strong>
even when the host cannot be trusted.</p>
<p>For institutional Safe users, Ledger applies the same principle directly. Its
<a href="https://www.ledger.com/blog-enterprise-beyond-the-quorum">Beyond the Quorum</a>
article identifies a compromised frontend as the threat and presents Clear
Signing as an independent view of a transaction’s true intent.</p>
<p><a href="/assets/images/blog/clear-signing-considered-harmful/ledger-enterprise-multisig-clear-signing.png"><img src="/assets/images/blog/clear-signing-considered-harmful/ledger-enterprise-multisig-clear-signing-framed.png" alt="Ledger Enterprise Multisig presents Clear Signing as the point where blind signing stops" /></a></p>
<p><em>Ledger Enterprise Multisig at
<a href="https://app.multisig.ledger.com/"><code class="language-plaintext highlighter-rouge">app.multisig.ledger.com</code></a>, captured on
2026-08-26. The product presents Clear Signing as the point where “blind
signing stops” for Safe transactions.</em></p>
<p>Clear Signing therefore sits at the final security boundary. When browser
JavaScript is compromised, the device must independently describe the
authorization it is about to sign.</p>
<p>The February 2025 Bybit theft made the compromised-frontend threat concrete.
<a href="https://www.sygnia.co/blog/sygnia-investigation-bybit-hack/">Sygnia’s public findings</a>
describe malicious JavaScript injected into resources served from Safe’s AWS
S3 bucket. The code manipulated the transaction initiated through Safe.
<a href="https://www.ledger.com/blog-learning-from-the-bybit-safe-attack">Ledger’s response</a>
presented trusted hardware display and Clear Signing as the layer that should
contain that failure mode.</p>
<blockquote>
<p>LEDGER_CLEAR_SIGNING_BYPASS reaches the same threat model through a different
failure mode: a compromised frontend supplies the payload, and device-side
Clear Signing produces a human-readable description that omits part of the
signed authorization.</p>
</blockquote>
<h2 id="2-the-parser-bug">2. The Parser Bug</h2>
<p>The vulnerability was in the shared array machinery of Ledger’s Ethereum
Generic Transaction Parser. The parser calculated an attacker-controlled array
pass count as a 16-bit integer, then stored it in an 8-bit countdown:</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">uint16_t</span> <span class="n">passes</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="n">passes_remaining</span><span class="p">[</span><span class="n">MAX_ARRAYS</span><span class="p">];</span>
<span class="n">passes_remaining</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="n">passes</span><span class="p">;</span>
</code></pre></div></div>
<p>For a 257-element array, the narrowing conversion changes <code class="language-plaintext highlighter-rouge">257</code> to <code class="language-plaintext highlighter-rouge">1</code>:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>passes = 257
(uint8_t)257 = 1
</code></pre></div></div>
<p>The parser then combines the full-width count with the truncated countdown to
select the first element it will review:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>idx = start + (passes - passes_remaining)
idx = 0 + (257 - 1)
idx = 256
</code></pre></div></div>
<p>The same truncated value controls iteration. Instead of starting at element
<code class="language-plaintext highlighter-rouge">0</code> and reviewing all 257 elements, the parser starts at element <code class="language-plaintext highlighter-rouge">256</code> and
reviews one. Elements <code class="language-plaintext highlighter-rouge">0</code> through <code class="language-plaintext highlighter-rouge">255</code> remain in the signed calldata but never
reach the trusted screen.</p>
<p>The behavior generalizes for any non-zero remainder:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>array length = N = 256q + k, where 1 <= k <= 255
displayed = final k elements = N mod 256
omitted = first 256q elements = N - (N mod 256)
</code></pre></div></div>
<p>The hidden prefix can contain different actions, mostly no-op calls surrounding
one consequential operation, or any other valid execution sequence that fits
the device’s constraints. The demonstrated Safe payload uses <code class="language-plaintext highlighter-rouge">q = 1</code> and
<code class="language-plaintext highlighter-rouge">k = 1</code>: the screen reviews one call while the signature authorizes 257.</p>
<p>The original fix is <a href="https://github.com/LedgerHQ/app-ethereum/commit/2c3d93cc35788f464ef8c641c2dbd30c5194697c">commit <code class="language-plaintext highlighter-rouge">2c3d93cc</code> — “Fix array iteration truncation”</a>.</p>
<h2 id="3-signed-metadata">3. Signed Metadata</h2>
<p>Clear Signing does not interpret every contract call generically. A transaction
enters this parser path only when a host-side Context Module supplies matching,
contract-specific metadata. That metadata tells the Ethereum app which intent,
fields, labels, paths, and formatting to render.</p>
<p>These Ledger-authorized descriptors make supported protocols legible on the
device. They also define the attack surface wherever they direct the vulnerable
parser through an attacker-controlled array.</p>
<p>In our August 25 snapshot, Ledger’s production dapp descriptor service
exposed array-backed <code class="language-plaintext highlighter-rouge">CALLDATA</code> fields for these transaction shapes:</p>
<table>
<thead>
<tr>
<th>Descriptor creator</th>
<th>Selector</th>
<th>Array field</th>
<th>Observed chains</th>
</tr>
</thead>
<tbody>
<tr>
<td>Safe</td>
<td><code class="language-plaintext highlighter-rouge">0x1a833ee3</code> (<code class="language-plaintext highlighter-rouge">batchExecute</code>)</td>
<td><code class="language-plaintext highlighter-rouge">Transaction</code> (<code class="language-plaintext highlighter-rouge">Call[]</code>)</td>
<td>Ethereum, Base, Optimism, Arbitrum, Polygon</td>
</tr>
<tr>
<td>Aave DAO</td>
<td><code class="language-plaintext highlighter-rouge">0xac9650d8</code> (<code class="language-plaintext highlighter-rouge">multicall</code>)</td>
<td><code class="language-plaintext highlighter-rouge">Call</code> (<code class="language-plaintext highlighter-rouge">bytes[]</code>)</td>
<td>Ethereum, Base, Optimism, Arbitrum, Polygon, Linea</td>
</tr>
<tr>
<td>Morpho DAO</td>
<td><code class="language-plaintext highlighter-rouge">0x374f435d</code> (<code class="language-plaintext highlighter-rouge">multicall</code>)</td>
<td><code class="language-plaintext highlighter-rouge">Action</code> (<code class="language-plaintext highlighter-rouge">bytes[]</code>)</td>
<td>Ethereum, Base</td>
</tr>
<tr>
<td>Morpho DAO</td>
<td><code class="language-plaintext highlighter-rouge">0x803a7fba</code> (<code class="language-plaintext highlighter-rouge">reallocate</code>)</td>
<td><code class="language-plaintext highlighter-rouge">Action</code> (<code class="language-plaintext highlighter-rouge">bytes[]</code>)</td>
<td>Ethereum, Base</td>
</tr>
</tbody>
</table>
<p>We demonstrated three paths through this surface:</p>
<table>
<thead>
<tr>
<th>Flow</th>
<th>Device displayed</th>
<th>Signature also authorized</th>
<th>Fork result</th>
</tr>
</thead>
<tbody>
<tr>
<td>Safe</td>
<td>Send 10 USDC</td>
<td>Maximum USDC allowance for the attacker</td>
<td>Safe accepted the authorization; the allowance was used to empty its remaining USDC balance</td>
</tr>
<tr>
<td>Aave</td>
<td>Supply 10 USDC</td>
<td>Withdraw the signer’s existing USDC supply position to the attacker</td>
<td>The exact affected-app transaction executed</td>
</tr>
<tr>
<td>Morpho</td>
<td>Supply 10 USDC</td>
<td>Withdraw the signer’s existing USDC position to the attacker</td>
<td>The exact affected-app transaction executed</td>
</tr>
</tbody>
</table>
<p>Safe is the main worked example because its array elements carry arbitrary
nested calls and its multi-owner treasury workflow makes the organizational
impact especially clear. Aave and Morpho extend the result beyond Safe and
EIP-712 authorization.</p>
<h2 id="4-safe">4. Safe</h2>
<p>Safe’s <code class="language-plaintext highlighter-rouge">BatchExecutor</code> provided a path from parser failure to treasury impact.
Its <code class="language-plaintext highlighter-rouge">batchExecute(Call[])</code> entry point accepts an array whose elements contain a
target, value, and arbitrary nested calldata. Ledger’s production Clear Signing
infrastructure supplied the archived
<a href="/assets/images/blog/clear-signing-considered-harmful/metadata/safe-batch-execute-ledger-signed-context.json"><code class="language-plaintext highlighter-rouge">batchExecute(Call[])</code> context</a>
for that transaction shape.</p>
<p>The operational threat is malicious JavaScript running inside an authorized
Safe frontend. The frontend constructs one attacker-chosen <code class="language-plaintext highlighter-rouge">SafeTx</code>, obtains
the accepted display context, and asks each required owner to sign the same
hash.</p>
<p>The attack path is:</p>
<ol>
<li>Malicious JavaScript runs inside the transaction frontend trusted by the
organization.</li>
<li>The browser presents a routine payment while sending an attacker-crafted
EIP-712 <code class="language-plaintext highlighter-rouge">SafeTx</code> to each required owner.</li>
<li>Each affected Ledger displays only the final batch action and returns a
valid signature over the complete hash.</li>
<li>Once the configured threshold is met, any relayer can submit the signed
<code class="language-plaintext highlighter-rouge">SafeTx</code> to Safe.</li>
<li>The hidden maximum allowance survives the displayed payment and lets the
approved spender transfer the remaining token balance.</li>
</ol>
<p>Safe still enforces its configured threshold and any independent guards or
policy controls. The exploitable failure is correlated semantic review: if the
owners rely on the same affected firmware and metadata path, every device can
repeat the same incomplete interpretation while contributing a valid signature
to the quorum.</p>
<p>The execution-critical fields in our proof were:</p>
<table>
<thead>
<tr>
<th><code class="language-plaintext highlighter-rouge">SafeTx</code> field</th>
<th>Signed value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="language-plaintext highlighter-rouge">to</code></td>
<td>Safe BatchExecutor</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">operation</code></td>
<td><code class="language-plaintext highlighter-rouge">DELEGATECALL</code> (<code class="language-plaintext highlighter-rouge">1</code>)</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">data</code></td>
<td>Pointer-aliased <code class="language-plaintext highlighter-rouge">batchExecute(Call[257])</code></td>
</tr>
</tbody>
</table>
<p>The affected application identified a Safe transaction and its nested batch,
displayed only the 10 USDC transfer, showed operation type <code class="language-plaintext highlighter-rouge">1</code>, and asked the
user to sign. It never displayed the maximum allowance in <code class="language-plaintext highlighter-rouge">SafeTx.data</code>.</p>
<p><img src="/assets/images/blog/clear-signing-considered-harmful/poc/safe-eip712-sequence.png" alt="Actual Safe EIP-712 review sequence from the executable LEDGER_CLEAR_SIGNING_BYPASS proof of concept" /></p>
<p><em>Actual Ragger frames from the affected Apex P review. Surrounding labels and
background are editorial.</em></p>
<p>Safe’s own <code class="language-plaintext highlighter-rouge">getTransactionHash</code> matched the hash signed by the Ledger. An
unrelated relayer submitted those fields and the recorded signature to a real
Safe <code class="language-plaintext highlighter-rouge">1.4.1</code> proxy on a pinned, disposable mainnet fork. The fork installed the
recovered Ledger address as the effective owner and set threshold <code class="language-plaintext highlighter-rouge">1</code>.</p>
<p>Execution emitted 256 undisplayed USDC <code class="language-plaintext highlighter-rouge">Approval</code> events, the displayed 10 USDC
<code class="language-plaintext highlighter-rouge">Transfer</code>, and <code class="language-plaintext highlighter-rouge">ExecutionSuccess</code>. The Safe nonce advanced and the attacker’s
allowance became <code class="language-plaintext highlighter-rouge">uint256.max</code>. A second local transaction then acted as the
approved spender and transferred the remaining USDC from the Safe.</p>
<p>That run proves a signature produced after an incomplete device review was
blockchain-usable.</p>
<h2 id="5-aave">5. Aave</h2>
<p>Aave V3’s archived
<a href="/assets/images/blog/clear-signing-considered-harmful/metadata/aave-v3-multicall-ledger-signed-context.json"><code class="language-plaintext highlighter-rouge">multicall(bytes[])</code> context</a>
provides a direct-transaction path through the same shared array parser.</p>
<p>A user opens a compromised frontend to supply 10 USDC to Aave. The browser
sends a 257-entry multicall to the Ledger. Entry <code class="language-plaintext highlighter-rouge">0</code> withdraws the user’s
existing USDC supply position to the attacker, entries <code class="language-plaintext highlighter-rouge">1</code> through <code class="language-plaintext highlighter-rouge">255</code>
reference aliased filler calls, and entry <code class="language-plaintext highlighter-rouge">256</code> performs the expected 10 USDC
supply.</p>
<p>With Ethereum app <code class="language-plaintext highlighter-rouge">1.22.2</code>, the parser starts at entry <code class="language-plaintext highlighter-rouge">256</code>. The device
displays the 10 USDC supply while its signature covers the complete multicall,
including the withdrawal. We submitted that exact signed transaction to a
pinned mainnet fork: the existing position moved to the attacker, and the
displayed supply completed.</p>
<p><img src="/assets/images/blog/clear-signing-considered-harmful/poc/aave-clear-signing-bypass.png" alt="Aave Clear Signing bypass: a 10 USDC supply displayed while an existing position is withdrawn" /></p>
<p><em>The affected app reviewed the final supply entry. The signed multicall also
contained the preceding withdrawal.</em></p>
<h2 id="6-morpho">6. Morpho</h2>
<p>Morpho’s archived Bundler3
<a href="/assets/images/blog/clear-signing-considered-harmful/metadata/morpho-bundler3-multicall-ledger-signed-context.json"><code class="language-plaintext highlighter-rouge">multicall</code> context</a>
supplied a second direct-transaction path through the vulnerable parser.</p>
<p>A user opens a compromised frontend to supply 10 USDC to a Morpho market. The
browser sends a 257-entry Bundler3 multicall to the Ledger. Entry <code class="language-plaintext highlighter-rouge">0</code> moves the
expected 10 USDC into Morpho’s adapter, entry <code class="language-plaintext highlighter-rouge">1</code> withdraws the user’s complete
existing USDC position to the attacker, entries <code class="language-plaintext highlighter-rouge">2</code> through <code class="language-plaintext highlighter-rouge">255</code> reference one
aliased no-op call, and entry <code class="language-plaintext highlighter-rouge">256</code> performs the expected 10 USDC supply for the
visible recipient.</p>
<p>With Ethereum app <code class="language-plaintext highlighter-rouge">1.22.2</code>, the parser starts at entry <code class="language-plaintext highlighter-rouge">256</code>. The device
displays the 10 USDC supply while its signature covers the complete multicall,
including the withdrawal. We submitted that exact signed transaction to the
pinned mainnet fork: the existing 100 USDC position moved to the attacker, the
displayed supply completed, and no residual USDC remained in the adapter.</p>
<p><img src="/assets/images/blog/clear-signing-considered-harmful/poc/morpho-clear-signing-bypass.png" alt="Morpho Clear Signing bypass: a 10 USDC supply displayed while an existing position is withdrawn" /></p>
<p><em>The affected app reviewed the final supply entry. The signed multicall also
contained the preceding funding call, withdrawal, and aliased no-op calls.</em></p>
<p>Aave and Morpho establish the same result through different transaction
shapes: the screen reviewed a suffix while the signature authorized the whole
array.</p>
<h2 id="7-making-257-calls-fit">7. Making 257 Calls Fit</h2>
<p>Practical exploitation also had to satisfy the device’s memory constraints.</p>
<p>A conventional <code class="language-plaintext highlighter-rouge">batchExecute(Call[257])</code> encoding repeats every dynamic tuple.
For the demonstrated ERC-20 calls, that produces 65,860 bytes, far beyond the
tested flow’s practical limit.</p>
<p><a href="/assets/images/blog/clear-signing-considered-harmful/poc/abi-calldata-01-heap.svg"><img src="/assets/images/blog/clear-signing-considered-harmful/poc/abi-calldata-01-heap.png" alt="Same-scale comparison of the naive 65,860-byte ABI encoding, the 16 KiB heap limit, and the 8,740-byte aliased encoding" /></a></p>
<p><em>The conventional encoding does not fit. Reusing tuple bodies brings the same
257 logical entries below the parser’s 16 KiB allocation.</em></p>
<p>ABI dynamic offsets allow multiple array entries to point to the same tuple. We
built an offset table in which the first 256 entries all point to one shared
approval tuple while the final entry points to one transfer tuple:</p>
<p><a href="/assets/images/blog/clear-signing-considered-harmful/poc/abi-calldata-02-offsets.svg"><img src="/assets/images/blog/clear-signing-considered-harmful/poc/abi-calldata-02-offsets.png" alt="ABI offset table showing 256 entries referencing hidden CALL_A and the final entry referencing displayed CALL_B" /></a></p>
<p><em>The offset table contains 257 entries, but the encoded payload stores only two
tuple bodies.</em></p>
<p>Aliasing reduced the calldata from <strong>65,860 bytes to 8,740 bytes</strong>, allowing it
to fit the original 16 KiB parser allocator. The signature still commits to all
257 logical array entries.</p>
<p>At execution, Safe invokes tuple A 256 times. Those calls repeatedly set the
same allowance, leaving one maximum approval. Tuple B performs the small
payment shown by the device. The approved spender can then call <code class="language-plaintext highlighter-rouge">transferFrom</code>
directly.</p>
<p><a href="/assets/images/blog/clear-signing-considered-harmful/poc/abi-calldata-03-divergence.svg"><img src="/assets/images/blog/clear-signing-considered-harmful/poc/abi-calldata-03-divergence.png" alt="Comparison of the truncated device review with the complete Safe and EVM interpretation committed to by the signature" /></a></p>
<p><em>The device starts at entry 256 and reviews the transfer. Safe interprets the
complete array, and the signature commits to both tuple bodies.</em></p>
<p>The signed descriptor remains authentic. The calldata remains valid ABI. The
signature remains cryptographically correct. The trusted interpretation omits
signed actions.</p>
<h2 id="8-proof-of-concept">8. Proof of Concept</h2>
<blockquote>
<p><strong>Before testing:</strong> Treat the PoC page and its outputs as untrusted. Use a
separate test device with a new, disposable seed phrase and no real funds.
Never use your everyday wallet or reuse its recovery phrase. Never enter a
seed phrase into the PoC page or any website.</p>
</blockquote>
<p>The <a href="/poc/ledger-clear-signing-bypass/">hardware signing artifact wizard</a>
presents the Safe, Aave, and Morpho proofs as three paths through one page. For
each protocol it reconstructs the canonical 257-element payload, requests a
fresh signature from a connected Ledger through WebHID, and verifies the
signer against the complete payload.</p>
<p>The page ships a frozen copy of the Ledger-signed production descriptors,
token metadata, and device certificates used by the demonstrations. It does
not query Ledger’s current metadata service and does not require a CAL origin
token. This preserves the historical Clear Signing inputs if the hosted
metadata changes or disappears.</p>
<p>The page keeps the evidence chain explicit: <strong>Select</strong>, <strong>Capture</strong>, <strong>Inspect</strong>,
and <strong>Export</strong>. Safe exports an EIP-712 owner authorization with every <code class="language-plaintext highlighter-rouge">SafeTx</code>
field and the corresponding <code class="language-plaintext highlighter-rouge">Safe.execTransaction</code> calldata. Aave and Morpho
export complete raw signed EIP-1559 transactions.</p>
<p>The page generates commands that consume the exported artifact through
independent Safe or DeFi runners on a pinned, disposable
Anvil fork.</p>
<p>The final result compares the device display, signed authorization, and local
execution:</p>
<ul>
<li><strong>Device display</strong>
<ul>
<li>Send 10 USDC</li>
</ul>
</li>
<li><strong>Signed authorization</strong>
<ul>
<li>Transfer 10 USDC</li>
<li>Approve attacker: MAX</li>
</ul>
</li>
<li><strong>Anvil result</strong>
<ul>
<li>Transfer completed</li>
<li>Allowance created</li>
<li>Safe balance: 0</li>
</ul>
</li>
</ul>
<p>A physical-device capture requires Chrome or Edge, an affected test device,
and a disposable seed. The fixed Ethereum app rejects the malformed array. The
page does not offer an archived-signature fallback.</p>
<h2 id="9-fix-and-release">9. Fix and Release</h2>
<p><a href="/assets/images/blog/clear-signing-considered-harmful/timeline.svg"><img src="/assets/images/blog/clear-signing-considered-harmful/timeline.png" alt="Remediation timeline showing the March report, May source correction, vulnerable 1.22.2 tag, and fixed 1.22.3 release" /></a></p>
<p>Ledger merged the root-cause correction into public <code class="language-plaintext highlighter-rouge">develop</code> on May 5. The
security-relevant change was a three-line bounds check:</p>
<div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">@@ -261,6 +261,9 @@</span> static bool path_array(const s_array_args *array,
*offset += 1;
if (arrays_info->index == arrays_info->depth) {
// new depth
<span class="gi">+ if (passes > UINT8_MAX) {
+ return false;
+ }
</span> arrays_info->passes_remaining[arrays_info->index] = passes;
arrays_info->depth += 1;
}
</code></pre></div></div>
<p>The first installable stable release containing the correction became available
on August 25.</p>
<p>On August 26, we gave only that patch hunk to a fresh, isolated Codex session
running <code class="language-plaintext highlighter-rouge">gpt-5.6-sol</code>. We omitted the commit title, repository, report,
surrounding declarations, and exploit details. Its first conclusion was:</p>
<blockquote>
<p>An unchecked narrowing conversion when storing <code class="language-plaintext highlighter-rouge">passes</code> in
<code class="language-plaintext highlighter-rouge">passes_remaining[]</code>.</p>
</blockquote>
<p>The model selected <code class="language-plaintext highlighter-rouge">256</code> as the first boundary test, identified <code class="language-plaintext highlighter-rouge">255</code> as the
valid maximum, and warned that the old code could select the wrong element or
stop traversal early. Reconstructing the complete exploit chain still required
surrounding source and human analysis. This single triage run illustrates how
the patch hunk alone enabled an agent to identify the bug class and critical
input boundary.</p>
<p>Source correction and user protection are separate milestones. GitHub’s
<a href="https://docs.github.com/en/code-security/concepts/vulnerability-reporting-and-management/repository-security-advisories">repository security advisory workflow</a>
supports private fix development, allowing a root-cause diff to remain private
until an installable release is ready.</p>
<p>The correction missed stable versions <code class="language-plaintext highlighter-rouge">1.22.1</code> and <code class="language-plaintext highlighter-rouge">1.22.2</code>.
Version <code class="language-plaintext highlighter-rouge">1.22.2</code> fixed a separate issue reported by TestMachine, but left this
bug unfixed.
For most of the agreed disclosure period, the correction was visible in public
Git history while users on the stable release remained affected.</p>
<p>We notified Ledger that the original PoC still reproduced on the exact
<code class="language-plaintext highlighter-rouge">1.22.2</code> tag. The fixed Ethereum app <code class="language-plaintext highlighter-rouge">1.22.3</code> became installable two days later,
on August 25. We retested it immediately and confirmed that the same PoC was
rejected. The full disclosure and remediation record is in the
<a href="#appendix-disclosure-record">appendix</a>.</p>
<p>We are publishing with fixed Ethereum app <code class="language-plaintext highlighter-rouge">1.22.3</code> available through Ledger’s
normal application catalog.</p>
<h2 id="10-conclusion-one-thing-well">10. Conclusion: One Thing Well</h2>
<p>Version <code class="language-plaintext highlighter-rouge">1.22.3</code> removes this truncation. The harder question remains: what
other bugs could emerge from the same firmware complexity?</p>
<p>Ledger’s default flow gives trusted firmware two security-critical jobs:</p>
<ol>
<li>protect and use the private key; and</li>
<li>interpret evolving smart-contract semantics for the user.</li>
</ol>
<p>The second job is substantial. A stateful C parser combines attacker-controlled
calldata with evolving metadata, walks nested structures, manages parser state,
formats values, and decides which facts deserve space on a small screen. Here,
one unchecked narrowing conversion changed 257 reviews into one. Each protocol
and display feature adds another opportunity for interpretation to diverge from
authorization.</p>
<p>Metadata signatures establish the provenance of rendering instructions.
Completeness, correct firmware interpretation, and correspondence between the
screen and every signed action remain separate security properties.</p>
<p>For multisig custody, identical devices create a shared semantic control. A
quorum can be cryptographically valid while every signer receives the same
wrong interpretation from the same firmware and metadata path.</p>
<p>Blind signing makes the absence of semantic verification visible. Incomplete
Clear Signing can instead present a readable interpretation that omits actions
covered by the signature.</p>
<p>A narrower hardware signer would protect keys, display one stable commitment,
and sign exactly that commitment. Decoding, simulation, policy evaluation, and
human-readable views could run across independent, replaceable systems that
bind their conclusions to the same hash.</p>
<h2 id="11-appendix-disclosure-record">11. Appendix: Disclosure Record</h2>
<p>Dates use <code class="language-plaintext highlighter-rouge">YYYY-MM-DD</code>. Times in the underlying correspondence are retained in
<code class="language-plaintext highlighter-rouge">America/Argentina/Cordoba</code> (<code class="language-plaintext highlighter-rouge">ART</code>, UTC-3). The table records confirmed email
exchanges and public GitHub or release activity.</p>
<table>
<thead>
<tr>
<th>Date</th>
<th>Record</th>
<th>Event</th>
</tr>
</thead>
<tbody>
<tr>
<td>2026-03-28</td>
<td>Email</td>
<td>Bitfinding submitted the encrypted report and PoC.</td>
</tr>
<tr>
<td>2026-03-31</td>
<td>Email</td>
<td>Ledger acknowledged receipt.</td>
</tr>
<tr>
<td>2026-04-22</td>
<td>Email</td>
<td>Bitfinding reported reproduction on Ethereum app <code class="language-plaintext highlighter-rouge">1.22.0</code>.</td>
</tr>
<tr>
<td>2026-04-23</td>
<td>Email</td>
<td>Ledger validated exploitability, classified the report High, and approved the maximum reward for the category. Bitfinding asked to publish the analysis and PoC after remediation and release.</td>
</tr>
<tr>
<td>2026-05-04</td>
<td>Email</td>
<td>Ledger agreed to post-remediation publication and requested a wait until early September. Bitfinding accepted.</td>
</tr>
<tr>
<td>2026-05-05</td>
<td>GitHub</td>
<td>Commit <a href="https://github.com/LedgerHQ/app-ethereum/commit/2c3d93cc35788f464ef8c641c2dbd30c5194697c"><code class="language-plaintext highlighter-rouge">2c3d93cc</code></a> merged the correction into public <code class="language-plaintext highlighter-rouge">develop</code> through <a href="https://github.com/LedgerHQ/app-ethereum/pull/1017">PR #1017</a>.</td>
</tr>
<tr>
<td>2026-05-27</td>
<td>GitHub</td>
<td>Version <code class="language-plaintext highlighter-rouge">1.22.1</code> did not include the fix.</td>
</tr>
<tr>
<td>2026-08-10 to 2026-08-13</td>
<td>GitHub / production catalog</td>
<td>Ledger prepared Ethereum app <code class="language-plaintext highlighter-rouge">1.22.2</code> to fix a separate issue reported by TestMachine.</td>
</tr>
<tr>
<td>2026-08-23</td>
<td>Email</td>
<td>Bitfinding reported that the correction was absent from <code class="language-plaintext highlighter-rouge">1.22.2</code> and <code class="language-plaintext highlighter-rouge">master</code>, requested the first installable fixed version, and reiterated first-week-of-September publication.</td>
</tr>
<tr>
<td>2026-08-24</td>
<td>Email / GitHub</td>
<td>Ledger confirmed that the correction had missed the release branch and treated the release-line feedback as a new bounty. A public <code class="language-plaintext highlighter-rouge">release/1.22.3</code> branch appeared with an equivalent backport.</td>
</tr>
<tr>
<td>2026-08-25</td>
<td>Email / GitHub / production catalog</td>
<td>Ledger described the original issue as partially fixed and requested Communications review. Fixed app <code class="language-plaintext highlighter-rouge">1.22.3</code> became available for Nano S Plus, Nano X, Stax, Flex, and Apex P. Bitfinding confirmed that the same PoC no longer reproduced.</td>
</tr>
<tr>
<td>2026-08-27</td>
<td>Public disclosure</td>
<td>Ledger published <a href="https://donjon.ledger.com/lsb/024/">LSB-024</a>, crediting Bitfinding and noting that Florian Pradines independently reported a variant. The bulletin covers the bug, affected versions, impact, fix, and coordinated-disclosure timeline.</td>
</tr>
<tr>
<td>2026-09-07</td>
<td>Publication</td>
<td>Bitfinding published this document, <em>Signature overflow attacks on Ledger</em>.</td>
</tr>
</tbody>
</table>]]></content><author><name>Bitfinding Research Team</name></author><summary type="html"><![CDATA[A Ledger Clear Signing parser bug let an affected device display one action while signing 257. We examine the Safe, Aave, and Morpho attack paths, practical exploitation, and the architectural implications.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bitfinding.com/assets/images/blog/signature-overflow-attacks-on-ledger/social.png" /><media:content medium="image" url="https://bitfinding.com/assets/images/blog/signature-overflow-attacks-on-ledger/social.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">$1M Intercepted from the Balancer Hack</title><link href="https://bitfinding.com/blog/balancer-exploit-interception/" rel="alternate" type="text/html" title="$1M Intercepted from the Balancer Hack" /><published>2025-11-11T00:00:00-03:00</published><updated>2025-11-11T00:00:00-03:00</updated><id>https://bitfinding.com/blog/balancer-exploit-interception</id><content type="html" xml:base="https://bitfinding.com/blog/balancer-exploit-interception/"><![CDATA[<p>On Monday, November 3rd, 2025, Bitfinding’s Exploit Interception Agent deployed countermeasures in less than 12 seconds, detecting and intercepting part of the exploits targeting Balancer’s V2 pools on the Ethereum chain. Our whitehat bot successfully secured over $975,000 in assets, preventing further losses in one of the year’s most sophisticated DeFi attacks. Notably, our initial intervention landed in the very next block after the attacker’s first exploit, highlighting the lightning-fast response of our system.</p>
<h2 id="the-attack-unfolds">The Attack Unfolds</h2>
<p>The Balancer exploit originated from a subtle rounding error in the protocol’s upscale function during EXACT_OUT swaps within Composable Stable Pools, allowing attackers to drain tokens like WETH, osETH, and wstETH from pools on Ethereum, Arbitrum, Base, and other networks.</p>
<p>For a detailed technical breakdown, see the explanations from <a href="https://blog.unvariant.io/balancer-hack-explained/">Unvariant</a> and <a href="https://www.coinspect.com/blog/balancer-rate-manipulation-exploit/">Coinspect</a>.</p>
<p>According to <a href="https://x.com/Balancer/status/1986104426667401241?s=20">Balancer’s preliminary postmortem</a>, the incident affected Composable Stable Pools across multiple networks, with immediate responses including pausing pools, freezing assets, and whitehat recoveries reducing the net impact. The root cause involved deferred settlement in batch swaps allowing extreme low-liquidity states, combined with the rounding flaw. Final losses were estimated around $98 million after mitigations, though initial exploits exceeded $128 million.</p>
<p>The vulnerability, undetected despite multiple audits, enabled attackers to artificially suppress pool token (BPT) values and arbitrage the discrepancies.</p>
<p><img src="/assets/images/blog/balancer-exploit-interception/funds_returned.png" alt="Unblind clear signing explanation" /></p>
<h2 id="timeline">Timeline</h2>
<table>
<thead>
<tr>
<th>UTC timestamp</th>
<th>Event</th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="language-plaintext highlighter-rouge">2025-11-03 07:46:47</code></td>
<td>Attacker executes initial exploit. Tokens Lost: 6,587.44 WETH , 6,851.12 osETH and 4,259.84 wstETH.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">2025-11-03 07:46:59</code></td>
<td>12 seconds later, Bitfinding’s Agent identifies, reconstructs the attack. Tokens Recovered: 135.856 WETH, 10.956 wstETH and 105.21 osETH.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">2025-11-03 08:33:47</code></td>
<td>Further interceptions. Tokens Recovered: 6.225 rETH, and 6.616 weETH.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">2025-11-03 11:19:00</code></td>
<td>Informed SEAL about the exploit, discussed with pcaversaccio, and got in touch with the Balancer team.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">2025-11-04 02:32:00</code></td>
<td>Send all the recovered funds to the Balancer DAO</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">2025-11-07 13:36:00</code></td>
<td>Balancer team informed us about additional stuck funds in the contract.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">2025-11-08 20:04:35</code></td>
<td>The remaining osETH are extracted and also sent to the Balancer DAO.</td>
</tr>
</tbody>
</table>
<p>A special shoutout to <a href="https://x.com/pcaversaccio">@pcaversaccio</a> for always being helpful and to the Balancer team (Danko, Fabio, Juani, and Daniel) for their collaboration throughout the return process.</p>
<h2 id="conclusion">Conclusion</h2>
<p>We’re grateful to have helped return funds to a core DeFi protocol. Our interception agent runs as a public good: it watches the chain in real time, models likely exploits, and when a pattern is confirmed it rebuilds the attacker’s path and tries to land a preemptive whitehat transaction first to move assets to safety. In this case it acted one block after the first exploit and secured about $1M.</p>
<p>Unblind applies the same concept to user signatures, protecting them from drainers, scams and mistakes. It explains transactions in plain language, flags unexpected behavior, and empowers users and platforms with the knowledge required to operate in hostile blockchain environments. If you run a wallet, custody platform, or DAO treasury and want this by default, Unblind easily integrates via API. Please <a href="#contact">get in touch below</a>.</p>]]></content><author><name>Bitfinding Team</name></author><summary type="html"><![CDATA[On November 3rd, Bitfinding's Exploit Interception Agent secured over $975,000 from the Balancer exploit, deploying countermeasures in less than 12 seconds after the attacker's first move and preventing further losses in one of the year's most sophisticated DeFi attacks.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bitfinding.com/assets/images/blog/balancer-exploit-interception/social.png" /><media:content medium="image" url="https://bitfinding.com/assets/images/blog/balancer-exploit-interception/social.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Unblind your Safe Dashboard</title><link href="https://bitfinding.com/blog/unblind-safe-dashboard/" rel="alternate" type="text/html" title="Unblind your Safe Dashboard" /><published>2025-10-16T00:00:00-03:00</published><updated>2025-10-16T00:00:00-03:00</updated><id>https://bitfinding.com/blog/unblind-safe-dashboard</id><content type="html" xml:base="https://bitfinding.com/blog/unblind-safe-dashboard/"><![CDATA[<p>We’re launching <a href="https://unblind.app/safe-dashboard">Unblind Safe Dashboard</a>, a simple utility to verify your pending Safe transactions. It uses <a href="https://unblind.app/">Unblind API</a> to translate cryptic data into plain English, ensuring you never have to sign blind again.</p>
<h2 id="the-easiest-security-upgrade-youll-ever-make">The Easiest Security Upgrade You’ll Ever Make</h2>
<p>We know that cumbersome security tools are often ignored. That’s why we designed the Unblind Dashboard with extreme simplicity in mind.</p>
<ul>
<li>
<p>If your Safe URL looks like this: <code class="language-plaintext highlighter-rouge">https://app.safe.global/transactions/queue?safe=arb1:0x...</code></p>
</li>
<li>
<p>Just add a <strong>“u”</strong> to the domain to access our dashboard: <code class="language-plaintext highlighter-rouge">https://app.usafe.global/transactions/queue?safe=arb1:0x...</code></p>
</li>
</ul>
<p>That’s it. No installation, no setup. Just one letter separates you from confusion to clarity. Review the human-readable explanations, and once you’re confident, proceed to sign in the <a href="https://app.safe.global">official Safe app</a>.</p>
<p><a href="https://drive.google.com/file/d/1ygNOU_2MrkgzxgFtYAKTnUDCJKV_2b3_/preview">Video: Unblind Safe Dashboard Demo</a></p>
<h2 id="the-multisig-paradox-secure-keys-blind-signatures">The Multisig Paradox: Secure Keys, Blind Signatures</h2>
<p>Even the best security practices, like using hardware wallet and a Safe multisig, have a critical flaw: you can’t always trust what you see on the screen. The infamous Bybit hack proved that a compromised or malicious UI can show you a harmless transaction while tricking you into signing a malicious one. Your multisig security means nothing if all signers are looking at the same deceptive interface.</p>
<p>These are the gold standard for asset protection. But even with a multisig, a fundamental problem remains: <strong><em>how can you trust that what you see on your screen is what you’re actually signing?</em></strong></p>
<p>Every time that wallet notification pops up asking for a signature, a moment of anxiety follows. <strong><em>Are we really approving a simple token swap, or are we accidentally giving away the keys to our digital kingdom?</em></strong></p>
<p>This is the exact problem we built Unblind to solve. Our engine goes beyond just decoding data; it simulates transactions, analyzes on-chain history, and pulls from multiple sources to translate a transaction’s true intent into plain English. The difference is night and day: an action like <strong><em>“Send 5 USDT to bill.eth”</em></strong> should look alarmingly different from <strong><em>“You are about to send 100,000 USDT to an unknown address”</em></strong>, and with Unblind, it does. If the explanation feels wrong, you cancel. It’s that simple.</p>
<p><img src="/assets/images/blog/unblind-safe-dashboard/unblind.png" alt="Unblind clear signing explanation" width="800" /></p>
<h2 id="introducing-the-unblind-safe-dashboard-your-independent-verification-layer">Introducing the Unblind Safe Dashboard: Your Independent Verification Layer</h2>
<p>To showcase Unblind’s power and provide a ready to use security tool for the community, we created the <strong>Unblind Safe Dashboard</strong>. It’s a read-only, alternative interface that translates your pending Safe transactions into plain English, so you know exactly what you’re signing.</p>
<p><img src="/assets/images/blog/unblind-safe-dashboard/bybit.png" alt="Unblind Safe Dashboard interface" width="1200" /></p>
<h2 id="what-makes-it-secure">What makes it secure?</h2>
<ul>
<li>
<p><strong>Independent Data Source:</strong> The dashboard pulls transaction data directly from the official Safe API. This means even if the primary app.safe.global interface were compromised or manipulated, our dashboard would show you the transaction’s true intent. This security model relies on the integrity of the Safe API itself, providing a crucial check against frontend-specific attacks.</p>
</li>
<li>
<p><strong>Out-of-Band Verification:</strong> For maximum security, you should view this dashboard on a separate device like your phone or tablet. If your main computer is compromised, this “out-of-band” check acts as an independent lifeline, allowing you to see the real details before you or your team approve a malicious transaction.</p>
</li>
</ul>
<table>
<thead>
<tr>
<th>Standard Safe UI</th>
<th>Unblind Safe Dashboard</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="/assets/images/blog/unblind-safe-dashboard/safe-dashboard.png" alt="Standard Safe UI" /></td>
<td><img src="/assets/images/blog/unblind-safe-dashboard/unblind-dashboard.png" alt="Unblind Safe Dashboard" /></td>
</tr>
</tbody>
</table>
<h2 id="this-is-just-the-beginning">This is Just the Beginning</h2>
<p>The <a href="https://unblind.app/safe-dashboard">Unblind Safe Dashboard</a> is more than just a tool for <a href="https://app.safe.global">Safe</a> users; it’s a demonstration of a future where no one has to sign a transaction blindly. This same Unblind engine can be integrated into any wallet, dApp, or platform to provide users with the clarity they need to navigate Web3 safely.</p>
<p><strong>We want to hear from you!</strong></p>
<ul>
<li><strong>Try it out:</strong> If you use a Safe, give our dashboard a try and let us know what you think.</li>
<li><strong>Feedback & Suggestions:</strong> How can we improve the dashboard? What other information would be useful?</li>
<li><strong>Builders & Wallets:</strong> If you’re building a product and want to eliminate user anxiety and enhance security, contact us to learn more about integrating Unblind.</li>
</ul>
<p>It’s time to replace signing anxiety with signing confidence.</p>]]></content><author><name>Bitfinding Team</name></author><summary type="html"><![CDATA[We're launching the Unblind Safe Dashboard, a simple utility to verify your pending Safe transactions. It uses Unblind API to translate cryptic data into plain English, ensuring you never have to sign blind again.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bitfinding.com/assets/images/blog/unblind-safe-dashboard/social.png" /><media:content medium="image" url="https://bitfinding.com/assets/images/blog/unblind-safe-dashboard/social.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Unblind Second Factor is now available</title><link href="https://bitfinding.com/blog/unblind-second-factor-snap/" rel="alternate" type="text/html" title="Unblind Second Factor is now available" /><published>2025-10-02T00:00:00-03:00</published><updated>2025-10-02T00:00:00-03:00</updated><id>https://bitfinding.com/blog/unblind-second-factor-snap</id><content type="html" xml:base="https://bitfinding.com/blog/unblind-second-factor-snap/"><![CDATA[<p>Crypto users face a constant threat: sophisticated phishing attacks and wallet drainers that trick them into signing away their assets. The core of this problem is the cryptic nature of signing requests, which even experienced users can misinterpret. To combat this, we built <strong>Unblind: an engine that explains any signing requests in plain English.</strong> This time we are releasing our <a href="https://snaps.metamask.io/snap/npm/bitfinding/unblind-second-factor-snap/">Metamask Snap</a> that delivers this human-readable summary via a secure, out-of-band Telegram message, arming you with the knowledge to approve or reject a transaction.</p>
<p>We previously discussed this in our <a href="https://bitfinding.com/blog/semantic-second-factor">previous blog post</a>.</p>
<p><a href="https://drive.google.com/file/d/1VsbKTh_fUoD5dlZhmTxacc8TRV-cK9xA/preview">Video: Unblind Second Factor Snap: How to install and use</a></p>
<p>You can install the Unblind Snap by visiting the <a href="https://snaps.metamask.io/snap/npm/bitfinding/unblind-second-factor-snap/">official MetaMask Snaps Directory</a>.</p>
<h2 id="why-translation-is-the-foundation-of-transaction-security">Why Translation is the Foundation of Transaction Security</h2>
<p>The typical security approach relies on blocklists, issuing generic warnings like “High-Risk Contract.” While these alerts can provide a useful signal, they are a fundamentally incomplete solution that often leads to alert fatigue.</p>
<ul>
<li><strong>False Positives:</strong> A brand-new, legitimate DeFi protocol might be flagged simply because it’s unknown, causing you to miss opportunities.</li>
<li><strong>False Negatives:</strong> A novel phishing scam might be marked as “safe” because it hasn’t been blocklisted yet, giving you a false sense of security.</li>
</ul>
<p>Reputation-based alerts create uncertainty. Our approach adds a foundational layer: <strong>clarity through high-fidelity translation.</strong></p>
<p>Unblind runs a powerful context extraction and simulation of the transactions and messages <strong>before you sign it</strong>. We don’t just show you data; we show you what that data is designed to do in a way that’s relevant to you. This simulation provides the core context that is missing from today’s signing experience, and it’s a layer upon which other signals, like reputation data, can be added for even greater security.</p>
<p>For example, when all the other alert systems failed at the time to warn about the Bybit hack, this is what our tool would have shown:</p>
<blockquote>
<p>“You will update the master copy of your Safe Wallet to 0xbdd077f651ebe7f7b3ce16fe5f2b025be2969516. This is an administrative action.”</p>
</blockquote>
<p>This shifts the power back to you. With a clear understanding of the transaction’s consequences, your decision to approve or reject becomes confident and informed.</p>
<h2 id="why-a-second-factor">Why a Second Factor</h2>
<p>Our primary goal is to protect you from approving malicious requests. A key security principle of Unblind is its function as an out-of-band verification channel.</p>
<p>If your browser, operating system, or even your software wallet is compromised, an attacker can display a fake transaction on your screen while submitting a malicious one in the background. Unblind defeats this vector. You will either receive no notification on your secondary device (Telegram), or you will receive a notification that accurately describes the <strong>actual malicious action</strong>.</p>
<p><strong>This discrepancy is your most critical alert.</strong> The absence of a matching message is an unambiguous signal to reject the signature request immediately. This protects you even when your primary device cannot be trusted.</p>
<h2 id="privacy-posture">Privacy Posture</h2>
<p>We respect user privacy and only store the minimal information needed to deliver these alerts to your Telegram.</p>
<p>However, for those who wish to avoid linking a Telegram account at all, Unblind offers a fully air-gapped verification method. This flow ensures your addresses and account information remain entirely separate.</p>
<p>The workflow is simple:</p>
<ol>
<li>When prompted to sign, select the “QR Code” option within the Unblind snap.</li>
<li>On a separate device (like a phone), open a web browser and navigate to <a href="https://unblind.app">https://unblind.app</a>.</li>
<li>Use this second device to scan the QR code displayed on your primary machine.</li>
<li>The human-readable translation will appear directly on your second device for verification, with no account or connection to your identity required.</li>
</ol>
<h2 id="our-mission-a-new-standard-for-digital-ownership">Our Mission: A New Standard for Digital Ownership</h2>
<p>The Unblind Snap for Metamask is just the beginning. Our mission is to protect <strong>every single user</strong> signing a transaction on any chain. We believe that human-readable, verifiable intent should not be an optional plugin, but a native, fundamental part of the digital ownership experience. True security should be invisible and universal.</p>
<p>For this to become a reality, we need to work together.</p>
<p><strong>For Our Users</strong></p>
<p>Your feedback on the current Snap is invaluable. Every suggestion helps us refine the core engine that will power this broader mission. Please continue to share your experiences with us. Join the <a href="https://t.me/+FdfFoJqOoJ4yYTYx">telegram group</a> or go to the <a href="https://forms.gle/1qJjTN9m4YKA4C2z8">anonymous form</a></p>
<p><strong>A Call to Builders: Partner with Us</strong></p>
<p>We are calling on wallet developers, dApps, and exchanges who share our vision. To make human-readable security a universal standard, we need to work together.</p>
<p>Unblind’s translation engine is not just a standalone tool; it’s a foundational security layer designed for integration. We offer a simple and powerful API that allows you to embed transaction simulations directly into your product.</p>
<p>By partnering with us, you can:</p>
<ul>
<li><strong>Enhance User Trust:</strong> Give your users the clarity to transact confidently.</li>
<li><strong>Reduce Support Overhead:</strong> Prevent security incidents caused by user error and phishing.</li>
<li><strong>Strengthen Your Brand:</strong> Signal that you prioritize user safety above all else.</li>
</ul>
<p>We are establishing an early partner program to make integration seamless. If you are building a product that involves signing requests, <a href="#contact">contact us</a>.</p>
<p>Let’s make fearless signing the default experience across the web3 ecosystem.</p>]]></content><author><name>Bitfinding Team</name></author><summary type="html"><![CDATA[Crypto users face a constant threat: sophisticated phishing attacks and wallet drainers that trick them into signing away their assets. The core of this problem is the cryptic nature of signing requests, which even experienced users can misinterpret. To combat this, we built Unblind: an engine that explains any signing requests in plain English. This time we are releasing our Metamask Snap that delivers this human-readable summary via a secure, out-of-band Telegram message, arming you with the knowledge to approve or reject a transaction.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bitfinding.com/assets/images/blog/unblind-second-factor/social.png" /><media:content medium="image" url="https://bitfinding.com/assets/images/blog/unblind-second-factor/social.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Enforcing Transaction Simulation Integrity: Pectra Edition</title><link href="https://bitfinding.com/blog/enforcing-transaction-simulation/" rel="alternate" type="text/html" title="Enforcing Transaction Simulation Integrity: Pectra Edition" /><published>2025-05-29T00:00:00-03:00</published><updated>2025-05-29T00:00:00-03:00</updated><id>https://bitfinding.com/blog/enforcing-transaction-simulation</id><content type="html" xml:base="https://bitfinding.com/blog/enforcing-transaction-simulation/"><![CDATA[<p>Imagine you’re about to swap a significant amount of ETH for USDT on a decentralized exchange (DEX). You use your wallet’s simulation feature, and it shows you’ll receive 1000 USDT, a good rate! You sign and send. But by the time your transaction hits the chain, a large trade has shifted the pool’s reserves, and your transaction either reverts or nets you only 950 USDT. This frustrating (and potentially costly) scenario highlights a critical flaw: <strong>simulations offer a snapshot, but the blockchain is a moving target</strong>.</p>
<p><img src="/assets/images/blog/enforcing-transaction-simulation/maybe_simulation.svg" alt="" /></p>
<p>The security of your blockchain interactions increasingly depends on validating these simulation outcomes. However, the core issue is their inability to enforce <strong><em>state consistency between the simulation and the actual execution</em></strong>. This gap can lead to vulnerabilities, especially when key contract states, like proxy implementations or DEX reserves, change unexpectedly.</p>
<p>This problem only gets worse now that Pectra has enabled multiple batch of calls in a single transaction making simulations far more complex.</p>
<h2 id="core-problem-state-divergence">Core Problem: State Divergence</h2>
<p>The central challenge is <strong>state divergence</strong>: critical smart contract states can change organically or adversarially between the time you simulate your transaction and when it’s actually mined on the blockchain.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>s0 = (calldata, contracts, state0)
s1 = (calldata, contracts, state1)
exec(s0) != exec(s1)
</code></pre></div></div>
<p>Several scenarios illustrate this risk:</p>
<ol>
<li><strong>Proxy Upgrade:</strong> Imagine you’re interacting with an NFT marketplace that uses a proxy contract (allowing logic upgrades). You simulate listing an NFT. Between simulation and execution, if the marketplace upgrades its implementation contract, new logic might interpret your data differently or change fees, leading to unexpected outcomes like lost funds or incorrect listings.</li>
<li><strong>DEX Reserve Shift:</strong> You simulate swapping 1 ETH for USDT on Uniswap, expecting 3000 USDT based on current reserves. If a large trade occurs just before your transaction, shifting pool reserves, your 1 ETH might yield only 2950 USDT, or the transaction could revert due to slippage.</li>
<li><strong>Oracle Value Update:</strong> Many DeFi protocols use oracles for price feeds (e.g., ETH/USD). You simulate borrowing against collateral, and the oracle price at simulation time is favorable. If the oracle updates with a lower price for your collateral right before execution, due to market volatility or manipulation, your transaction might fail or put you at immediate risk of liquidation.</li>
</ol>
<h2 id="attacking-simulation-reliance">Attacking Simulation Reliance</h2>
<p>Wallets and security tools are increasingly relying on transaction simulations to protect users. By previewing the outcome of complex smart contract interactions, simulations aim to prevent users from signing malicious transactions. However, this reliance introduces its own set of challenges and potential vulnerabilities.</p>
<p><img src="/assets/images/blog/enforcing-transaction-simulation/state_divergence.jpg" alt="TODO" /></p>
<p>A <a href="https://zengo.com/wp-content/uploads/Web3-Transaction-Simulation-White-Paper-Final.pdf">white paper by Zengo funded by the Ethereum Foundation</a> highlights critical limitations. While simulation is a valuable tool, it’s not foolproof. Attackers can exploit both theoretical constraints and practical implementation issues. One notable vulnerability is the “Red Pill Attack,” where a malicious contract detects it’s running in a simulated environment. It behaves benignly during the simulation, lulling the user into a false sense of security, but then executes its malicious payload once on the actual blockchain. This deception can lead users to approve harmful transactions they believe are safe.</p>
<p>This underscores that while simulations enhance security, they can also create a deceptive safety net if their limitations are not understood and addressed. <strong>The integrity of the simulation environment itself becomes a target for sophisticated attackers</strong>.</p>
<h2 id="enter-state-constraints">Enter State Constraints</h2>
<p>To bridge this simulation-to-execution gap more robustly, we propose that transactions carry not just their execution data (the “what to do”) but also a compact set of <strong>state constraints</strong> (the “under these conditions”). These constraints act as on-chain guards: the transaction asserts them before proceeding, reverting early if the underlying assumptions from your simulation no longer hold.</p>
<p>These constraints can be written using a Domain Specific Language (DSL) designed to be expressive yet simple:</p>
<table>
<thead>
<tr>
<th>Constraint</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="language-plaintext highlighter-rouge">TokenAddress.balanceOf($AccountAddress) >= 10000</code></td>
<td>checks an expected token balance.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">ProxyAddress.implementation() == $ExpectedImplementationAddress</code></td>
<td>verifies a proxy’s logic hasn’t changed.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">block.timestamp < 1720000000</code></td>
<td>acts as a soft deadline for time-sensitive transactions.</td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">storageSlot($ContractAddress, $StorageSlot) == $ExpectedValue</code></td>
<td>ensures a specific storage slot remains unchanged, more on this later!</td>
</tr>
</tbody>
</table>
<p>At runtime, these constraint checks are performed first. <strong>If all pass, the main transaction logic proceeds. If any fails, the entire transaction reverts, preventing unintended outcomes</strong>.</p>
<h2 id="step-by-step-from-simulation-to-trusted-execution">Step by Step: From Simulation to Trusted Execution</h2>
<p>Let’s walk through how this works, using our DEX trade and proxy upgrade examples.</p>
<p><strong>1. Transaction Simulation & Intent Representation</strong></p>
<p>When you initiate a transaction, your wallet software performs a simulation. Crucially, the tooling also identifies key blockchain state your transaction <em>depends on</em> like <strong>storages, environment, balances, nonces, etc</strong>. These are translated into conditions using a DSL.</p>
<ul>
<li><em>DeFi Trade Example:</em> Swap 1 ETH for at least 2950 USDT. Simulation shows 3000 USDT based on current reserves.</li>
<li><em>Proxy Upgrade Example:</em> List an NFT for 5 ETH. Simulation uses marketplace implementation <code class="language-plaintext highlighter-rouge">$GOOD_CONTRACT_V1</code>.</li>
</ul>
<p><img src="/assets/images/blog/enforcing-transaction-simulation/diagram.svg" alt="TODO" /></p>
<p><strong>2. Extracting the State Constraints</strong></p>
<p>The simulation engine analyzes relied-upon state and extracts these as explicit constraints.</p>
<ul>
<li><em>DeFi Trade Example DSL:</em></li>
</ul>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Preconditions: Ensure DEX pool state is as expected
900 < WETH.balanceOf($PairAddress) < 1100
2,900,000 < USDT.balanceOf($PairAddress) < 3,100,000
// Postcondition: Ensure user receives minimum USDT
USDT.balanceOf($UserAddress) >= $oldBalanceOfUSDT + 3000
</code></pre></div></div>
<ul>
<li><em>Proxy Upgrade Example Constraint:</em></li>
</ul>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Preconditions: Ensure proxy implementation matches the simulation
MarketProxyAddress.implementation() == $GOOD_CONTRACT_V1
</code></pre></div></div>
<p><strong>3. Transaction Packaging</strong></p>
<p>The final transaction, with constraints, is packaged using a multicall provided by the users’ wallet (ERC-4337 UserOperation) or delegating to a contract (EIP-7702). This effectively structures the transaction as:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Constraint Pre-checks] -> [Original Transaction Logic] -> [Constraint Post-checks (optional)]
</code></pre></div></div>
<p><strong>4. Signing the Enhanced Transaction</strong></p>
<p>The user can now simulate the transaction in different settings. The outcome will either stay true to user expectations or revert if the on-chain conditions no longer match the simulation. The user sees a simulation outcome, similar to what wallets show, but this one can be trusted because the constraints are bundled with the transaction. This entire package, including the constraints, is presented for review before the user signs.</p>
<p><strong>5. Constraint Enforcement On-Chain</strong></p>
<p>When executed: pre-checks compare current on-chain state against your constraints. For example, if DEX reserves shifted too much or the proxy changed, a constraint fails. If any violation occurs, the transaction reverts <em>before</em> main logic runs. If all pass, main logic executes, followed by post-condition checks.</p>
<h2 id="why-this-works-better-now">Why This Works (Better Now)</h2>
<p>This approach of embedding state constraints becomes particularly powerful and user-friendly due to recent Ethereum improvements, offering several key advantages:</p>
<ul>
<li>
<p><strong>Atomicity and Improved User Experience:</strong> The Pectra upgrade, through EIP-7702, <strong>makes Smart Account functionalities accessible to EOAs</strong> through delegation. This allows bundling multiple calls (constraint checks <em>and</em> main actions) into one atomic transaction, ensuring all-or-nothing execution with a single signature.</p>
</li>
<li>
<p><strong>Backward Compatibility:</strong> This system works with existing smart contracts. The constraint checking logic lives in a separate contract that only requires an extra call with the constraints to check.</p>
</li>
<li>
<p><strong>Cost Efficiency:</strong> Reading storage or calling <code class="language-plaintext highlighter-rouge">view</code> functions multiple times within the same transaction is relatively cheap. The gas for these checks is often a small price for significantly enhanced security.</p>
</li>
<li>
<p><strong>Granular Control:</strong> You can enforce exact matches for critical state (like a proxy’s implementation) and acceptable ranges for volatile state (like DEX reserves within slippage tolerance).</p>
</li>
</ul>
<h2 id="the-dream-low-level-storage-checks">The Dream: Low-Level Storage Checks</h2>
<p>Currently, state checks often rely on public <code class="language-plaintext highlighter-rouge">getter</code> functions. This is limited because the contract must expose the state via a truthful getter, and cross-contract calls can be gas-intensive. For example, if a proxy doesn’t expose the implementation() function, we can’t check it!</p>
<p>For truly robust, universal, and gas-efficient enforcement, direct, low-level access to read raw storage from other contracts is needed: The concept of an <strong>EXTSLOAD</strong> opcode <a href="https://eips.ethereum.org/EIPS/eip-2330">as previously discussed in this EIP</a> would tackle all these challenges.</p>
<p>Alternatively, standardized interfaces like <strong><code class="language-plaintext highlighter-rouge">IExtsload</code></strong> (e.g., in UniswapX/Uniswap v4 research) also offer gas-efficient batch state reads:</p>
<div class="language-solidity highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">interface</span> <span class="n">IExtsload</span> <span class="p">{</span>
<span class="k">function</span> <span class="n">extsload</span><span class="p">(</span><span class="kt">bytes32</span> <span class="n">slot</span><span class="p">)</span> <span class="k">external</span> <span class="k">view</span> <span class="k">returns</span> <span class="p">(</span><span class="kt">bytes32</span> <span class="n">value</span><span class="p">);</span>
<span class="k">function</span> <span class="n">extsload</span><span class="p">(</span><span class="kt">bytes32</span> <span class="n">startSlot</span><span class="p">,</span> <span class="kt">uint256</span> <span class="n">nSlots</span><span class="p">)</span> <span class="k">external</span> <span class="k">view</span> <span class="k">returns</span> <span class="p">(</span><span class="kt">bytes32</span><span class="p">[]</span> <span class="k">memory</span> <span class="n">values</span><span class="p">);</span>
<span class="k">function</span> <span class="n">extsload</span><span class="p">(</span><span class="kt">bytes32</span><span class="p">[]</span> <span class="k">calldata</span> <span class="n">slots</span><span class="p">)</span> <span class="k">external</span> <span class="k">view</span> <span class="k">returns</span> <span class="p">(</span><span class="kt">bytes32</span><span class="p">[]</span> <span class="k">memory</span> <span class="n">values</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>While still a contract call, standardization would improve efficiency. Native EVM support would be the ultimate goal.</p>
<h2 id="takeaways--whats-next">Takeaways & What’s Next</h2>
<p>Enforcing transaction simulation integrity is crucial for user safety in the dynamic world of blockchain.</p>
<ul>
<li>State divergence between simulation and execution is critical.</li>
<li>Attaching explicit state constraints to transactions acts as an on-chain safeguard, ensuring assumptions hold.</li>
<li>EIP-7702, ERC-4337 and EIP-5792 provide the ideal framework for bundling constraint checks with main transaction logic atomically and with good UX.</li>
<li>This method is backward-compatible and can be gas-efficient, making it practical for widespread adoption.</li>
<li>Future EVM improvements for direct external state reads will make this approach even more powerful and affordable.</li>
</ul>
<p>At Bitfinding, we are <strong>experts in low-level EVM execution for security and optimization</strong>. We are prototyping these state constraint principles with our <a href="https://bitfinding.com/blog/semantic-second-factor">simulation engine</a>. We are actively working on moving the EVM ecosystem forward to prevent hacks through research and innovative services.</p>
<p><strong>If you’re interested in integrating this solution to protect yourself or your users, or want to discuss how to make your dApp interactions safer, we’d love your feedback or to explore collaboration.</strong></p>]]></content><author><name>Bitfinding Team</name></author><summary type="html"><![CDATA[Transaction simulations can be misleading due to 'state divergence' - critical on-chain conditions changing post-simulation. This post explores how to enforce simulation integrity by embedding 'state constraints' within transactions, leveraging EIP-7702 and ERC-4337, to ensure your intended outcomes are what you actually get on-chain.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://bitfinding.com/assets/images/blog/enforcing-transaction-simulation/social.png" /><media:content medium="image" url="https://bitfinding.com/assets/images/blog/enforcing-transaction-simulation/social.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Open Sourcing our MEV Launchpad: Multiplexer</title><link href="https://bitfinding.com/blog/open-sourcing-multiplexer/" rel="alternate" type="text/html" title="Open Sourcing our MEV Launchpad: Multiplexer" /><published>2025-04-25T00:00:00-03:00</published><updated>2025-04-25T00:00:00-03:00</updated><id>https://bitfinding.com/blog/open-sourcing-multiplexer</id><content type="html" xml:base="https://bitfinding.com/blog/open-sourcing-multiplexer/"><![CDATA[<p>Trying to nail that perfect arbitrage, execute a complex multi-step DeFi strategy, or even simulate a frontrunning attack often means wrestling with multiple transactions, timing risks, and callback hell.</p>
<p>We faced these challenges constantly while intercepting attacks at Bitfinding. That’s why we created Multiplexer, our internal engine for crafting powerful, precise, atomic Ethereum operations. Today, we’re proud to open source it for everyone.</p>
<p>👉 <a href="https://github.com/Bitfinding/multiplexer">github.com/Bitfinding/multiplexer</a></p>
<h2 id="what-does-multiplexer-actually-do">What does Multiplexer actually do?</h2>
<p>Think of Multiplexer as <strong>multicall on steroids</strong>. It’s a smart contract that acts like a mini virtual machine executing a list of instructions you provide. You can pack an incredible amount into one transaction:</p>
<p>🔗 <strong>Batch calls (<code class="language-plaintext highlighter-rouge">CALL</code>, <code class="language-plaintext highlighter-rouge">DELEGATECALL</code>)</strong> to interact with any contract.</p>
<p>🚀 <strong>Deploy new contracts (<code class="language-plaintext highlighter-rouge">CREATE</code>)</strong> that can be used in the same transaction.</p>
<p>⚡ <strong>Handle Flash Loans</strong> from providers like Morpho and Aave, including managing the required callbacks seamlessly.</p>