Feb 14, 2026·6 min read·55 visits
CometBFT's 'BFT Time' calculation failed to verify that timestamps came from active validators. An attacker can skew the block time forward, breaking smart contracts and vesting logic.
A critical consensus vulnerability in CometBFT allows malicious proposers to manipulate the blockchain's internal clock ('BFT Time') by injecting invalid signatures into block commits. This 'Tachyon' attack bypasses validator set verification during time calculation, enabling attackers to artificially advance block timestamps and potentially trigger premature vesting or disrupt time-sensitive smart contracts.
In the world of distributed systems, 'time' is a messy hallucination we all agree to share. For blockchains built on the Cosmos stack, that hallucination is maintained by CometBFT (formerly Tendermint). It doesn't rely on NTP or a central atomic clock; instead, it uses a deterministic algorithm called BFT Time. This is supposed to be the bedrock of the chain—a weighted median of timestamps provided by validators in the previous block.
Why does this matter? Because everything in DeFi relies on it. Unbonding periods, vesting schedules, oracle updates, and governance timeouts all query this ctx.BlockTime(). If you control the clock, you don't just control the history; you control the future assets of the chain.
Enter GHSA-C32P-WCQJ-J677, alias 'Tachyon'. It turns out that the mechanism CometBFT used to calculate this median time was a little too trusting. It assumed that the data fed into the time calculation was strictly from the VIP list (the active validator set). It wasn't. This vulnerability is the equivalent of letting a random passerby yell the time into the room, and the blockchain deciding, 'Yeah, sounds about right.'
The core of the issue lies in how MedianTime is calculated. In CometBFT, the timestamp for Block $H$ is derived from the Precommit votes of Block $H-1$. The logic is sound in theory: take the weighted median of the timestamps from the validators who signed the previous block. This prevents a single malicious validator with 1% voting power from setting the time to the year 3000.
However, the implementation had a gaping logic error. The function responsible for calculating this median iterated through the signatures in the LastCommit structure, but it failed to strictly enforce membership checks against the active validator set during the calculation phase.
A malicious block proposer could craft a LastCommit that included signatures with valid structures but wild timestamps. Because MakeBlock (the block construction method) didn't force MedianTime to validate that every timestamp contributor was actually allowed to vote, the algorithm happily ingested these outliers. The math works perfectly—it calculates the median—but the input data is poisoned. It's a classic case of 'Garbage In, Garbage Out,' except the garbage is a timestamp set to unlock your vesting tokens three years early.
Let's look at the smoking gun in state/state.go. The vulnerability stems from a lack of error propagation and validation context.
Before the Fix:
The MedianTime function likely returned a time value without complaining, even if the input data was sketchy. The MakeBlock function would simply take this value and stamp it onto the new block.
After the Fix (Commit bf8274f):
The developers introduced a hard stop. MedianTime now cross-references the signatures against state.LastValidators. If a signature claims to be from Index 5, the code checks if the address actually matches the validator at Index 5. Crucially, MakeBlock now handles errors returned by MedianTime.
Here is the diff that saves the ecosystem:
// state/state.go
func (state State) MakeBlock(...) (*types.Block, error) {
// ... snip ...
// The fix introduces error handling here
ts, err := MedianTime(lastCommit, state.LastValidators)
if err != nil {
// Now we panic/error out instead of creating a broken block
return nil, fmt.Errorf("error making block while calculating median time: %w", err)
}
timestamp = ts
// ... snip ...
}Furthermore, deep in types/validation.go, checks were added to ensure that commit.Signatures[i] corresponds strictly to the validator at that index. If the proposer tries to inject a 'ghost' signature to skew the time, the validation logic now throws a ErrInvalidCommitSignature.
So, how do we weaponize this? You need to be a Validator with proposing rights (or have compromised one). The attack vector isn't about breaking cryptography; it's about abusing the state machine's logic.
The Attack Chain:
LastCommit for the previous block. They collect real signatures from honest validators (to ensure the block passes validity checks), but they interleave or append crafted entries. These entries contain timestamps set far in the future.MedianTime function includes them in the weighted list.block.timestamp, see that the 'future' has arrived, and release funds. The attacker unbonds instantly or triggers time-based arbitrage opportunities.The severity of this bug cannot be overstated for an application-specific blockchain. In standard web apps, a wrong clock might mess up your logs. In crypto, time is money.
The fact that this was labeled 'Critical' and 'Catastrophic' by the maintainers suggests they found a working PoC that could reliably trigger these conditions in a live network.
The remediation is straightforward but essential: Validation must happen at the source.
The patch ensures that MedianTime is no longer a passive calculator. It acts as a gatekeeper. It explicitly verifies that every timestamp contributing to the median comes from a legitimate, active validator. If the Proposer tries to slip in a fake vote to skew the math, the function returns an error, the block creation fails, and the attack is neutralized.
Action Plan:
v0.37.18 or v0.38.21.ErrInvalidCommitSignature or failures in MakeBlock. This could indicate someone tried to exploit this against your node.CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
CometBFT CometBFT | < 0.37.18 | 0.37.18 |
CometBFT CometBFT | 0.38.0 - 0.38.20 | 0.38.21 |
| Attribute | Detail |
|---|---|
| CWE | CWE-665: Improper Initialization |
| Attack Vector | Network (Consensus Layer) |
| CVSS | 9.0 (Critical) |
| Impact | Consensus Failure / Logic Manipulation |
| Components | state/state.go, types/validation.go |
| Fix Commit | bf8274fcdbcab2bc652660ae627196a90a6efb97 |
The product does not initialize or incorrectly initializes a resource, which may leave the resource in an unexpected state.
CVE-2026-115895 is a high-severity code injection vulnerability (CWE-94) in the happy-dom npm package prior to version 21.0.4. The vulnerability exists within the ECMAScriptModuleCompiler component, which transforms ECMAScript module syntax into executable Node.js functions when JavaScript evaluation is enabled. Due to an incomplete fix for CVE-2026-33943, the compiler failed to validate local named import aliases against legal JavaScript identifier rules. Attackers supplying crafted module imports—specifically utilizing destructuring default initializers alongside JSON module attributes—can inject arbitrary JavaScript expressions directly into the host Node.js runtime context.
An improper input validation and authorization bypass vulnerability exists in the LangGraph storage layer affecting langgraph, langgraph-checkpoint-postgres, and langgraph-checkpoint-sqlite. Because relational store implementations serialize namespace tuples into dot-delimited strings without validating labels on read, search, delete, and batch operations, an attacker who controls a namespace label can inject periods (.) to traverse namespace boundaries and access, modify, or delete data belonging to other namespaces.
CVE-2026-115886 (GHSA-2wqp-q3c6-ccj5) is a Server-Side Request Forgery (SSRF) and Unsafe Reflection vulnerability in MLflow versions 3.12.0rc0 prior to 3.17.0. Unauthenticated REST API endpoints accept serialized third-party scorer JSON payloads that are dynamically deserialized and reflectively instantiated without sanitizing constructor keyword arguments. When optional dependencies such as trulens and trulens-providers-litellm are installed, attackers can inject egress-steering arguments into the scorer payload, forcing the MLflow server to dispatch outbound HTTP requests to arbitrary internal destinations or cloud metadata services.
CVE-2026-113872 (GHSA-q7qp-rjg7-q26m) is a high-severity denial-of-service vulnerability affecting the multer multipart/form-data upload middleware for Node.js and Express in versions 2.0.0 through 2.4.0. When an endpoint is configured to accept multiple files using an asynchronous fileFilter callback, a crafted, truncated multipart HTTP request can trigger an unhandled error event on the underlying busboy stream parser after request teardown has already completed. Because all error listeners are stripped during teardown, Node.js treats the resulting error event as an uncaught exception and immediately terminates the server process.
CVE-2026-115897 (also tracked as GHSA-m5mm-p8h7-m29v and aliased as CVE-2026-115754) is a Cross-Site Scripting (XSS) vulnerability in the Yahoo serialize-javascript npm package prior to version 7.1.3. The flaw exists in the regular expression used by escapeFunctionBody() to neutralize HTML script closing tags within serialized JavaScript functions. Because function bodies are sanitized in isolation before structural formatting is applied, a function whose string representation terminates directly with the sequence '</script' bypasses the positive lookahead check. When combined with serialization formatting options that introduce whitespace delimiters and a subsequent property that supplies a closing bracket, an attacker can prematurely terminate an enclosing HTML <script> block and inject arbitrary HTML or JavaScript into the rendered document.
CVE-2026-109841 is a Subresource Integrity (SRI) verification bypass vulnerability in undici, the official HTTP/1.1 and HTTP/2 client library for Node.js that powers the global fetch() implementation. The flaw stems from improper handling of case sensitivity (CWE-178) when validating cryptographic hash algorithm tokens within SRI metadata. Because undici compared incoming algorithm identifiers against a strictly lowercase set without prior ASCII-lowercase normalization, valid uppercase or mixed-case tokens such as SHA256- or Sha384- were treated as unrecognized algorithms and discarded. Under SRI forward-compatibility rules, discarding all provided tokens results in an empty integrity list, causing undici to fail open and accept tampered HTTP response bodies without cryptographic verification.