GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GCVE-1988-2026-0212

Vulnerability from gna-1988 – Published: 2026-09-08 07:57 – Updated: 2026-09-08 07:57
VLAI
Title
Firedancer Solana Validator - QUIC Transport Parameter UB and Consensus-Splitting Cast Bug
Summary
1. SUMMARY Two independently confirmed vulnerabilities in Jump Crypto's Firedancer Solana validator (https://github.com/firedancer-io/firedancer, commit 7cd3b6dce): A) Three undefined behavior / logic bugs in QUIC transport parameter processing, triggerable by a malicious QUIC server with zero authentication. Enables remote connection kill or hang. B) Incorrect Rust saturating cast emulation that returns ULONG_MAX instead of 0 for negative infinity, diverging from Agave's behavior in rent and stake calculations. Potential consensus split. Both bugs were confirmed with UBSAN stack traces against the real compiled Firedancer source code and, for (B), cross-verified against rustc output. 2. BUG A: QUIC TRANSPORT PARAMETER UNDEFINED BEHAVIOR Affected file: src/waltz/quic/fd_quic.c Function: fd_quic_apply_peer_params (line 2667) Entry point: fd_quic_tls_cb_peer_params (line 2738), called during TLS handshake -- no authentication required. Three bugs, all triggered from a single malicious TLS handshake: --- A1: Signed integer overflow (line 2713) --- long peer_max_idle_timeout_ns = (long)peer_tp->max_idle_timeout_ms * (long)1e6; max_idle_timeout_ms is a ulong decoded from a QUIC VARINT (max 2^62-1). Cast to signed long, then multiplied by 1e6. For values above LONG_MAX/1e6 (~9.22e12), this is signed integer overflow -- undefined behavior per C11 6.5/5. UBSAN output: src/waltz/quic/fd_quic.c:2713:72: runtime error: signed integer overflow: 9223372036855 * 1000000 cannot be represented in type 'long' #0 in fd_quic_apply_peer_params fd_quic.c:2713 In practice, the result wraps negative. fd_long_min then selects this negative value as the idle timeout, causing immediate connection death. --- A2: Shift exponent too large (line 2724) --- conn->peer_ack_delay_scale = (float)( 1UL << peer_ack_delay_exponent ) * 1e3f; RFC 9000 Section 18.2: "Values above 20 are invalid." No validation is performed. For exponent >= 64, this is undefined behavior (shift amount = width of unsigned long). For 20 < exponent < 64, the scale becomes absurdly large (e.g., 4.6e+21 for exponent=62), corrupting all RTT estimation and loss detection. UBSAN output: src/waltz/quic/fd_quic.c:2724:45: runtime error: shift exponent 64 is too large for 64-bit type 'unsigned long' #0 in fd_quic_apply_peer_params fd_quic.c:2724 --- A3: Unsigned overflow in max_ack_delay (line 2730) --- peer_tp->max_ack_delay * 1000UL RFC 9000 Section 18.2: "Values of 2^14 or greater are invalid." No validation is performed. For large VARINT values, the multiplication wraps. The result, cast to float, produces a value on the order of 1e22 nanoseconds. This propagates to PTO calculation (fd_quic_private.h:429), making the probe timeout effectively infinite. The client never retransmits. --- Combined impact --- A malicious QUIC server sends these transport parameters in one TLS handshake: max_idle_timeout = 9223372036855 ms ack_delay_exponent = 64 max_ack_delay = 2^62 - 1 ms Result: the Firedancer QUIC client's connection is immediately killed (A1), its RTT estimation is destroyed (A2), and it will never retransmit (A3). This is a zero-interaction remote DoS requiring no authentication. --- Fix --- Validate per RFC 9000 Section 18.2 before use: - Reject ack_delay_exponent > 20 as TRANSPORT_PARAMETER_ERROR - Reject max_ack_delay >= 2^14 as TRANSPORT_PARAMETER_ERROR - Use unsigned arithmetic or clamp max_idle_timeout_ms before multiplying by 1e6 3. BUG B: fd_rust_cast_double_to_ulong RETURNS ULONG_MAX FOR -INFINITY Affected file: src/flamenco/types/fd_cast.h Function: fd_rust_cast_double_to_ulong (line 21) The function's own documentation (line 17-18) states: "Saturate to 0 if the value is negative or NaN." The implementation checks for infinity (bexp == 0x7FF, mant == 0) at line 24 and returns ULONG_MAX at line 27 without checking the sign bit. Both +inf and -inf hit this path. The sign check at line 35 is dead code for -inf because the function already returned. Firedancer: fd_rust_cast_double_to_ulong(-INFINITY) = 18446744073709551615 Rust (1.45+): (-f64::INFINITY as u64) = 0 Cross-verified by compiling and running the equivalent Rust program. The existing test (test_cast.c:17) encodes the incorrect behavior: FD_TEST( fd_rust_cast_double_to_ulong( ninf ) == ULONG_MAX ); This function is used in: - fd_sysvar_rent1.c:12 (rent exempt minimum balance) - fd_stake_program.c:551 (stake warmup) - fd_stake_program.c:636 (stake cooldown) - fd_runtime.c:525 (rent calculation) Current call sites use non-negative intermediates, so -infinity is unlikely to occur today. However, the function's contract is violated and any future call site producing a negative-infinity intermediate would cause a consensus split between Firedancer and Agave. --- Fix --- In the infinity branch (line 26-27), check the sign bit: if( fd_dblbits_mant( u )==0 ) { return fd_dblbits_sign( u ) ? 0UL : ULONG_MAX; } Update test_cast.c:17 to assert the correct result: FD_TEST( fd_rust_cast_double_to_ulong( ninf ) == 0 ); 4. TIMELINE 2025-02-07 Bugs identified and POCs developed 2025-02-07 Attempted disclosure to Immunefi; unable to validate researcher identity 2025-02-08 Attempted disclosure to Immunefi; unable to validate researcher identity 2025-02-09 Attempted disclosure to Immunefi; unable to validate researcher identity 2025-02-09 Agent Spooky votes on Full Disclosure; measure passes unanimously. 2025-02-10 Full Disclosure happens. 5. CREDIT AGENT SPOOKY AND YOUR MOM Cheers! Agent Spooky's Fun Parade P.S. SHOUT OUT TO IMMUNEFI FOR BEING YOUR TYPICAL RUN OF THE MILL CRYPTO BRO HUSTLERS AKA PUNK ASS BITCHES. WE WON'T FORGIVE. WE WON'T FORGET. ALL YOUR CRYPTO ARE BELONG TO US. _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Impacted products
Vendor Product Version CPE status
unknown Firedancer Solana Validator Affected: unknown
guessed Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "Firedancer Solana Validator",
          "vendor": "unknown",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Agent Spooky\u0027s Fun Parade via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "1. SUMMARY\n\nTwo independently confirmed vulnerabilities in Jump Crypto\u0027s Firedancer\nSolana validator (https://github.com/firedancer-io/firedancer, commit\n7cd3b6dce):\n\n  A) Three undefined behavior / logic bugs in QUIC transport parameter\n     processing, triggerable by a malicious QUIC server with zero\n     authentication. Enables remote connection kill or hang.\n\n  B) Incorrect Rust saturating cast emulation that returns ULONG_MAX\n     instead of 0 for negative infinity, diverging from Agave\u0027s behavior\n     in rent and stake calculations. Potential consensus split.\n\nBoth bugs were confirmed with UBSAN stack traces against the real\ncompiled Firedancer source code and, for (B), cross-verified against\nrustc output.\n\n\n2. BUG A: QUIC TRANSPORT PARAMETER UNDEFINED BEHAVIOR\n\nAffected file: src/waltz/quic/fd_quic.c\nFunction: fd_quic_apply_peer_params (line 2667)\nEntry point: fd_quic_tls_cb_peer_params (line 2738), called during\n  TLS handshake -- no authentication required.\n\nThree bugs, all triggered from a single malicious TLS handshake:\n\n--- A1: Signed integer overflow (line 2713) ---\n\n  long peer_max_idle_timeout_ns = (long)peer_tp-\u003emax_idle_timeout_ms * (long)1e6;\n\nmax_idle_timeout_ms is a ulong decoded from a QUIC VARINT (max 2^62-1).\nCast to signed long, then multiplied by 1e6. For values above\nLONG_MAX/1e6 (~9.22e12), this is signed integer overflow -- undefined\nbehavior per C11 6.5/5.\n\nUBSAN output:\n\n  src/waltz/quic/fd_quic.c:2713:72: runtime error: signed integer\n  overflow: 9223372036855 * 1000000 cannot be represented in type \u0027long\u0027\n      #0 in fd_quic_apply_peer_params fd_quic.c:2713\n\nIn practice, the result wraps negative. fd_long_min then selects this\nnegative value as the idle timeout, causing immediate connection death.\n\n--- A2: Shift exponent too large (line 2724) ---\n\n  conn-\u003epeer_ack_delay_scale = (float)( 1UL \u003c\u003c peer_ack_delay_exponent ) * 1e3f;\n\nRFC 9000 Section 18.2: \"Values above 20 are invalid.\" No validation is\nperformed. For exponent \u003e= 64, this is undefined behavior (shift amount\n= width of unsigned long). For 20 \u003c exponent \u003c 64, the scale becomes\nabsurdly large (e.g., 4.6e+21 for exponent=62), corrupting all RTT\nestimation and loss detection.\n\nUBSAN output:\n\n  src/waltz/quic/fd_quic.c:2724:45: runtime error: shift exponent 64\n  is too large for 64-bit type \u0027unsigned long\u0027\n      #0 in fd_quic_apply_peer_params fd_quic.c:2724\n\n--- A3: Unsigned overflow in max_ack_delay (line 2730) ---\n\n  peer_tp-\u003emax_ack_delay * 1000UL\n\nRFC 9000 Section 18.2: \"Values of 2^14 or greater are invalid.\" No\nvalidation is performed. For large VARINT values, the multiplication\nwraps. The result, cast to float, produces a value on the order of 1e22\nnanoseconds. This propagates to PTO calculation (fd_quic_private.h:429),\nmaking the probe timeout effectively infinite. The client never\nretransmits.\n\n--- Combined impact ---\n\nA malicious QUIC server sends these transport parameters in one TLS\nhandshake:\n\n  max_idle_timeout    = 9223372036855 ms\n  ack_delay_exponent  = 64\n  max_ack_delay       = 2^62 - 1 ms\n\nResult: the Firedancer QUIC client\u0027s connection is immediately killed\n(A1), its RTT estimation is destroyed (A2), and it will never\nretransmit (A3). This is a zero-interaction remote DoS requiring no\nauthentication.\n\n--- Fix ---\n\nValidate per RFC 9000 Section 18.2 before use:\n  - Reject ack_delay_exponent \u003e 20 as TRANSPORT_PARAMETER_ERROR\n  - Reject max_ack_delay \u003e= 2^14 as TRANSPORT_PARAMETER_ERROR\n  - Use unsigned arithmetic or clamp max_idle_timeout_ms before\n    multiplying by 1e6\n\n\n3. BUG B: fd_rust_cast_double_to_ulong RETURNS ULONG_MAX FOR -INFINITY\n\nAffected file: src/flamenco/types/fd_cast.h\nFunction: fd_rust_cast_double_to_ulong (line 21)\n\nThe function\u0027s own documentation (line 17-18) states:\n  \"Saturate to 0 if the value is negative or NaN.\"\n\nThe implementation checks for infinity (bexp == 0x7FF, mant == 0) at\nline 24 and returns ULONG_MAX at line 27 without checking the sign bit.\nBoth +inf and -inf hit this path. The sign check at line 35 is dead code\nfor -inf because the function already returned.\n\nFiredancer:  fd_rust_cast_double_to_ulong(-INFINITY) = 18446744073709551615\nRust (1.45+): (-f64::INFINITY as u64)                = 0\n\nCross-verified by compiling and running the equivalent Rust program.\n\nThe existing test (test_cast.c:17) encodes the incorrect behavior:\n  FD_TEST( fd_rust_cast_double_to_ulong( ninf ) == ULONG_MAX );\n\nThis function is used in:\n  - fd_sysvar_rent1.c:12   (rent exempt minimum balance)\n  - fd_stake_program.c:551 (stake warmup)\n  - fd_stake_program.c:636 (stake cooldown)\n  - fd_runtime.c:525       (rent calculation)\n\nCurrent call sites use non-negative intermediates, so -infinity is\nunlikely to occur today. However, the function\u0027s contract is violated\nand any future call site producing a negative-infinity intermediate\nwould cause a consensus split between Firedancer and Agave.\n\n--- Fix ---\n\nIn the infinity branch (line 26-27), check the sign bit:\n\n  if( fd_dblbits_mant( u )==0 ) {\n    return fd_dblbits_sign( u ) ? 0UL : ULONG_MAX;\n  }\n\nUpdate test_cast.c:17 to assert the correct result:\n  FD_TEST( fd_rust_cast_double_to_ulong( ninf ) == 0 );\n\n\n4. TIMELINE\n\n2025-02-07  Bugs identified and POCs developed\n2025-02-07  Attempted disclosure to Immunefi; unable to validate researcher identity\n2025-02-08  Attempted disclosure to Immunefi; unable to validate researcher identity\n2025-02-09  Attempted disclosure to Immunefi; unable to validate researcher identity\n2025-02-09  Agent Spooky votes on Full Disclosure; measure passes unanimously.\n2025-02-10  Full Disclosure happens.\n\n\n5. CREDIT\n\nAGENT SPOOKY AND YOUR MOM\n\n\nCheers!\n\nAgent Spooky\u0027s Fun Parade\n\n\nP.S.\u00a0SHOUT OUT TO IMMUNEFI FOR BEING YOUR TYPICAL RUN OF THE MILL CRYPTO BRO HUSTLERS AKA PUNK ASS BITCHES. \nWE WON\u0027T FORGIVE. WE WON\u0027T FORGET. ALL YOUR CRYPTO ARE BELONG TO US.\n\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-09-08T07:57:42Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Feb/14"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Feb/14"
        },
        {
          "url": "https://github.com/firedancer-io/firedancer"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Feb/14"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "Firedancer Solana Validator - QUIC Transport Parameter UB and Consensus-Splitting Cast Bug",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0212",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Feb/14",
            "automated": true,
            "contentSha256": "5900a228e970ba89ba3fc5395d8c927ecc2f91af3330a85946660f3c81d91aaf",
            "evidenceScore": 7,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Feb/14",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-02-10T16:08:58Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-09-08T07:57:42Z",
    "dateUpdated": "2026-09-08T07:57:42Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0212"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Loading…