Datachain security record

BNB Chain, Ethereumdatachain.jp

As of 30 Oct 2026, Datachain has 7 audit reports by 1 security firm on Trustblock; the latest is by Quantstamp, dated 25 Jul 2025. Those reports list no open critical findings.

Critical findings
No open critical findings
Across 7 reports.
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Trustblock does not review code.

Audits7

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Datachain - ELC for Bridge (OptimismELC)Security firm: QuantstampDate: Scope: Not recorded (see the report)No open critical findingsOpen · certificate.quantstamp.com
Datachain LCP-zkDCAPSecurity firm: QuantstampDate: Scope: Files named in the reportNo open critical findingsOpen · certificate.quantstamp.com
Datachain - App for LiquiditySecurity firm: QuantstampDate: Scope: Repository at commit dcccb98No open critical findingsOpen · certificate.quantstamp.com
Datachain - ELC for Bridge - EthereumSecurity firm: QuantstampDate: Scope: Repository at commit 7a40e6aNo open critical findingsOpen · certificate.quantstamp.com
Datachain - IBCSecurity firm: QuantstampDate: Scope: Repository at commit ca7a56cNo open critical findingsOpen · certificate.quantstamp.com
Datachain - LCPsSecurity firm: QuantstampDate: Scope: Repository at commit 54d2bacNo open critical findingsOpen · certificate.quantstamp.com
Datachain - ELC For Bridge - BSCSecurity firm: QuantstampDate: Scope: Repository at commit 78d1349No open critical findingsOpen · certificate.quantstamp.com

Findings65

Statuses are the security firm’s own, from each report.

SeverityOpenAcknowledgedFixed
Critical000
High017
Medium117
Low0741
HighPools are not always replenishedDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

`_deltaSourceUpdate()` is designed to apply the `deltaCredit` to replenish the soft partitions of the liquidity pool. The `diff` between the target total balance and current balance (the deficit) is calculated for each pool. `deltaCredit` is then applied to replenish each pool according to their weights. However, if `fullMode == true` and `totalDiff <= deltaCredit`, the `diff[i]` is never applied to `amtToCredit`. In this scenario, only the `excessCredit` is distributed to the pools. The inline and NatSpec comments further validate that this is a missing requirement.

Open the report
HighThe Drift protocol fee is prohibitively expensiveDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

The expected value of arbitraging a price drift between two pegged assets is equal to: ```js expectedValue = (dstPrice - srcPrice) * amountGD ``` The protocol drift fee is equal to: ```js (amountGd * srcPrice) / dstPrice ``` The current calculation far overcharges the protocol drift fee.

Open the report
High`IBCChannelHandshake.channelOpenAck()` Does Not Require Connection to Be Open Before Opening ChannelDatachain - IBC · Quantstamp · 9 Dec 2024Fixed

`IBCChannelHandshake.channelOpenAck()` does not confirm that the connection is open before opening the channel. As a result, an ibc-solidity chain can open a channel although the connection in which it resides is not open. This is a fundamental flaw as the connection handshake must be complete before any packets can be sent or received through it to ensure that two ConnectionEnds between chains are totally in sync. Additionally, creating a channel on a connection that hasn't completed the handshake will totally bypass all logic contained in `IBCConnection.connectionOpenConfirm()`. Another impact is that if the channel were created in this fashion, from the ChannelEnd on ChainB, `channelCloseInit()` could never be invoked, as this function requires that the `ConnectionEnd.State == STATE_OPEN`, which could result in the ChainB ChannelEnd being forced to continously receive what could be malicious packets from a counterparty. Throughout this implementation there is a missing enforcement of an open connection as defined in the specs as the Datachain team incorrectly assumes that an open channel implies an open connection. The comment `// NOTE: We can assume here that the connection state is OPEN because the channel state is OPEN` notes all places in the codebase where this assumption is made. Resolving this issue will allow this assumption to hold true, and we have not identified such a clear exploit resulting from the missing checks, however, we encourage the Datachain team to take a closer look here.

Open the report
HighClosing an Ordered Channel on Packet Timeout Is Not Reflected in the Provable StoreDatachain - IBC · Quantstamp · 9 Dec 2024Fixed

In the function `IBCChannelPacketTimeout.timeoutPacket()`, when closing an ordered channel due to packet timeout, the closed channel state is not written to the provable store. This creates the possibility for counterparty chains to be able to verify a different state of this channel that what is intended.

Open the report
HighMissing Logic for `STATE_FLUSHING` Channel StateDatachain - IBC · Quantstamp · 9 Dec 2024Fixed

During several packet operations there is missing logic in the ibc-solidity implementation when the Channel is in the `STATE_FLUSHING` state and actively completing an upgrade. According to the specs, this logic enforces a counterparty upgrade timeout. The logic is missing from the `acknowledgePacket()` and `timeoutPacket()` functions.

Open the report
HighNo Error if Commitment Exists in `updateClientCommitments()`Datachain - IBC · Quantstamp · 9 Dec 2024Fixed

`IBCClient.updateClientCommitments()` does not enforce that the `commitments` mapping is zero for the `consensusStateCommitmentKey` that is trying to be written. This is directly contradictory to what is documented in ADR-001 by the Datachain team. Perhaps, if the key exists, and is equivalent to the consensus state we derived from the light client, it would make sense to continue. However, the existence of the key with a different consensus state should signal that there is something out of sync between the clients. For example, in the case of a reorg, there could be a consensus state written at that key that is from a malicious series of blocks, that can be accepted as valid state alongside valid blocks.

Open the report
HighPacket Commitment Not Deleted in `timeoutOnClose()`Datachain - IBC · Quantstamp · 9 Dec 2024Fixed

The two functions `timeoutPacket()` and `timeoutOnClose()` first check if a packet's timeout has been exceeded, and if so, update the channel's state accordingly. In order to avoid replaying the same timeout multiple times, the packet's commitment key can be removed after use, as is suggested for both functions in the [ICS-04 specification](https://github.com/cosmos/ibc/blob/47fea20d4d400e967721396092c6b43398c65d78/spec/core/ics-004-channel-and-packet-semantics/README.md). However, this check does not occur in `timeoutOnClose()`. Note that if `timeoutOnClose()` is called multiple times for the same packet, the following module call will occur each time: ``` lookupModuleByChannel(msg_.packet.sourcePort, msg_.packet.sourceChannel).onTimeoutPacket( msg_.packet, _msgSender() ``` Since we cannot know how each different module will handle this call, this replay scenario should be avoided. This could be particularly problematic if the module refunds a user's tokens in this scenario.

Open the report
MediumCase-Sensitive TDX Module Identity Comparison May Cause Valid Attestations to FailDatachain LCP-zkDCAP · Quantstamp · 8 Apr 2025Fixed

In the `check_tdx_module_tcb_status` function, a TDX module identity ID is generated using lowercase hexadecimal formatting: ```rust let tdx_module_identity_id = format!("TDX_{:02x}", tdx_module_version); ``` This identifier is then used in a direct string comparison when filtering module identities: ```rust .filter(|m| m.id == tdx_module_identity_id) ``` The reference C++ implementation in Intel's SGX-TDX-DCAP-QuoteVerificationLibrary explicitly normalizes string case before comparison: ```cpp std::string id = tdxModuleIdentity.getId(); std::transform(id.begin(), id.end(), id.begin(), ::toupper); return (id == tdxModuleIdentityId); ``` If a mismatch occurs due to case sensitivity: - The function will not find a matching TDX module identity - It will return `TdxModuleTcbValidationStatus::TcbNotSupported` - This will likely cause legitimate TDX attestations to fail verification While this is not a security vulnerability allowing unauthorized access, it is a correctness issue that could impact system functionality by causing false rejections of valid attestations.

Open the report
MediumFailed transactions cause a drift in target balanceDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

When a failed transaction can no longer be retried, a permanent difference between the last known balance on the destination chain and the balance on the source chain grows by the value of the failed transaction, such that: ```js chainA.peerPoolInfo[chainB].lastKnownBalance >= chainB.peerPoolInfo[chainA].balance + totalFailedTransfers ``` The last known balance is used to determine how much a pool needs to be replenished in the delta algorithm. When the last known balance is greater than the actual balance available, the pool is underestimating how much liquidity is needed to replenish the pool. This gap will grow larger as the number of locked funds due to failed crosschain transactions increase over time. While pools can be rebalanced to accomodate for bandwidth requirements, many of the fees depend on accurately assessing pool health. A pool that seems to be closer to its target balance than it is in actuality cannot accurately manage incentives through fees.

Open the report
MediumFunction in `BridgeFallback` Reverts During Retry Due to `onlySelf` ModifierDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

The `BridgeFallback` contract uses the `onlySelf` modifier to restrict access to its `addRevert*()` functions, intending for these functions to be called only internally within the `BridgeFallback` contract itself. However, the `retryOnReceive` function, designed to retry failed cross-chain operations, attempts to call these `addRevert*()` functions when a retry fails, using a `try-catch` block. In that case, the `msg.sender` will be the external caller of `retryOnReceive`, not the `BridgeFallback` contract itself. This causes a revert, because the `onlySelf` modifier evaluates as false.

Open the report
Show 10 more
MediumLack of Price Feed Staleness ValidationDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

The `TokenPriceOracle` contract retrieves price data from `Chainlink` price feeds but lacks validation checks for stale or outdated price data. This could lead to the usage of outdated prices in critical operations if the price feed experiences delays or issues.

Open the report
Medium`timeoutPacket()` and `timeoutOnClose()` Incorrectly Enforce an Open Channel StateDatachain - IBC · Quantstamp · 9 Dec 2024Fixed

As the protocol is intended to support optimistic packet sends, that will be sent on channels that will either open in the future, or never open, there should be support for the timing out of packets on channels that are in a state different than `OPEN`. However, these two functions incorrectly enforce an open channel state.

Open the report
MediumMissing Checks on `revision_number`Datachain - IBC · Quantstamp · 9 Dec 2024Fixed

A packet is expected to have either a nonzero `timeoutHeight` or a nonzero `timeoutTimestamp`. An example of this check occurs in `sendPacket()`: `timeoutHeight.isZero() && timeoutTimestamp == 0`. Notably, the call to `isZero()` checks both `revision_number` and `revision_height`. There are several other locations in the code that do not check the `revision_number`, such as in `recvPacket()`: `if (msg_.packet.timeoutHeight.revision_height != 0 && block.number >= msg_.packet.timeoutHeight.revision_height)`. If the `revision_number != 0` but `revision_height = 0`, it may allow a packet from an earlier revision to be received after its time out. In the worst case, this could lead to a double-spend, such that the sending chain refunds a user based on timeout, and the receiving chain later accepts a timed-out packet. Although the attack window is small and unlikely, as it requires a zero-height upgrade and a packet to be sent in block zero, the impact could be significant if used for an attack such as a double-spend. Another function that does not check `revision_number` is `timeoutChannelUpgrade()`: ``` if ( upgrade.timeout.height.revision_height != 0 && msg_.proofHeight.revision_height < upgrade.timeout.height.revision_height ) ``` Note that "zero-height upgrades" are possible, as described in [ICS-07](https://github.com/cosmos/ibc/blob/main/spec/client/ics-007-tendermint-client/README.md): "This is designed to allow the height to reset to 0 while the revision number increases by one in order to preserve timeouts through zero-height upgrades."

Open the report
MediumUntrusted Epochs Can Be Exploited by One Malicious Validator, Resulting in Finalization of Incorrect BlocksDatachain - ELC For Bridge - BSC · Quantstamp · 6 Dec 2024Fixed

Suppose we want to finalize a target block `x` with reference to a trusted block `w`. In order to finalize `x`, it is required to provide a consecutive sequence of headers starting at `x` and ending in two adjacent headers (call them the "finalizing blocks" `y` and `z`) that contain BLS signatures from their corresponding active validator set. At the start of every epoch, a new validator set is elected. This validator set becomes active once an epoch-specific checkpoint is reached: before the checkpoint, headers must be signed by validators from the trusted epoch; starting from the checkpoint, headers are required to be signed by the new validator set; before the checkpoint, BLS signatures used to finalize blocks must come from validators of the trusted epoch; *after* the checkpoint, such BLS signatures must come from the new validator set. This process updates with every subsequent validator set election. Ordinarily, finalizing incorrect blocks is difficult because 14 out of 21 validators of an active validator set would need to sign BLS signatures for two consecutive blocks in order to finalize a block that comes prior. The light client also ensures that at least 8 validators in an untrusted epoch are from the previous trusted epoch. However, it appears to be possible for one malicious validator, Alice, to introduce 13 malicious validators into an untrusted validator set along with herself in the following scenarios. Along with (or inside) an incorrect target block, Alice transmits a fake new validator set and a sequence of fake headers that she signs herself in order to pass the `verify_seal()` check, up to and including the checkpoint. She will also submit finalizing headers post-checkpoint with BLS signatures coming from the malicious validator set, meeting quorum. See the "Exploit Scenario" section below for an example-based explanation of the issue. In the worst case, the finalization of incorrect blocks may impact components of the LCP project that rely on the light client for correct data: for example, if a bridge were to be fed incorrect data regarding the state of the `IBCStore`'s storage root, it could be assumed that messages were broadcast when they in fact weren't, resulting in, for example, the issuing of funds on a destination chain without the appropriate conditions.

Open the report
LowConsistency of `RollupConfig`Datachain - ELC for Bridge (OptimismELC) · Quantstamp · 25 Jul 2025Fixed

The `Derivation` object is stateless regarding `RollupConfig`. When `lightclient::Header::verify_l2` calls `self.derivation.verify()`, it uses the `rollup_config` from the `ClientState`. The preimages provided in the `Header` and the derivation claim fields must have been generated by an off-chain prover using a `RollupConfig` that is identical to the one held in the `ClientState`. Therefore, if a relayer provides a `Header` whose embedded preimages or derivation claims were generated using a different `RollupConfig` than the one the `ClientState` is configured with, the verification performed by `Derivation::verify()` might lead to incorrect results. The code itself passes the `ClientState`'s `rollup_config`, but the validity of the operation hinges on the external consistency of the supplied `Header` data with this configuration.

Open the report
LowDuplicate Values Are Not Checked in `try_from()` for `MemoryOracleClient`Datachain - ELC for Bridge (OptimismELC) · Quantstamp · 25 Jul 2025Fixed

The `try_from()` function implemented for `MemoryOracleClient` loops on the `value` vector of preimages. The logic does not validate for duplicate preimages before operating on them, which may result in unwanted or broken behavior.

Open the report
LowGlobal Generic and Local Keytypes Are AllowedDatachain - ELC for Bridge (OptimismELC) · Quantstamp · 25 Jul 2025Fixed

The `try_from()` function implemented for `MemoryOracleClient` matches the `preimage_key.key_type()` value against the `PreimageKeyType::Keccak256` and `PreimageKeyType::Sha256` keytypes to validate them before including them in the oracle; however, the `_ => {}` arm would allow any other keytype to be included in the oracle without validation.

Open the report
LowLack of Length Validation in `verify_blob_preimage()`Datachain - ELC for Bridge (OptimismELC) · Quantstamp · 25 Jul 2025Fixed

Validation in `verify_blob_preimage()` can be added with respect to a number of attributes: 1. At `oracle.rs#L176`, when `blob_key` is instantiated, it is expected to have length `POSITION_FIELD_ELEMENT + 8`, i.e. `80`, when calling `get_data_by_blob_key(blob_key, preimages)`. 2. At `oracle.rs#L195`, `sidecar_blob` is expected to have length `32` when copying it into `blob` slices. Validating the length of these data is useful to prevent runtime panics that may arise in the case of malformed data.

Open the report
LowLack of Validation of the `frozen` and `revision_height` Values in `try_from()` for `ClientState`Datachain - ELC for Bridge (OptimismELC) · Quantstamp · 25 Jul 2025Fixed

The `try_from()` function implemented for `ClientState` accepts the value of `raw_latest_height.revision_height` from the latest height passed via the `value` provided without validation, which could be zero. Similarly, the value of `value.frozen` is not checked before being set in the generated `ClientState` instance, allowing for the creation of an initially frozen client.

Open the report
LowMisbehaviour Handling Not ImplementedDatachain - ELC for Bridge (OptimismELC) · Quantstamp · 25 Jul 2025Fixed

The `update_client()` function has a `todo!()` for `ClientMessage::Misbehaviour`. Hence, the light client cannot currently process or react to misbehaviour reports.

Open the report
Show 10 more
LowMissing Lower Bound Check in Timestamp ValidationDatachain - ELC for Bridge (OptimismELC) · Quantstamp · 25 Jul 2025Fixed

The name of the `validate_state_timestamp_within_trusting_period()` function suggests it is supposed to ensure that `current_timestamp` is within a valid range defined by `trusting_period`. While the function checks that the `current_timestamp` is not too far in the future (i.e., it enforces an upper bound), it fails to ensure that the timestamp is also recent enough to be trusted (i.e., within the lower bound of the `trusting_period`). This could allow outdated or expired state timestamps to pass validation erroneously.

Open the report
LowNondeterministic `verify_blob_preimage()`Datachain - ELC for Bridge (OptimismELC) · Quantstamp · 25 Jul 2025Fixed

Currently, when calling `verify_blob_preimage()`, the value of the last 32 bytes of `blob_key` when instantiated at `oracle.rs#L176` can in principle be arbitrary so long as the commitment within the first 48 bytes is correct. Although the function remains safe due to KZG verification, it may cause the client to accept preimages that other clients would reject, resulting in a subtle impact regarding client interoperability.

Open the report
LowChain Validation Against Common Name and Not Distinguished NameDatachain LCP-zkDCAP · Quantstamp · 8 Apr 2025Fixed

The `validate_pck_cert()` function currently relies on the Common Name (CN) to match certificates within the chain. This approach introduces potential security risks, as the CN alone is neither unique nor sufficient to unambiguously identify a certificate. Matching solely on CN can result in ambiguity and open the door to certain attacks, such as an adversary creating a certificate with the same CN as a trusted one. According to [RFC 5280, section 4.1.2.4](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4), the Distinguished Name (DN) should be used instead: > "Certificate users MUST be prepared to process the issuer distinguished name and subject distinguished name (Section 4.1.2.6) fields to perform name chaining for certification path validation. Name chaining is performed by matching the issuer distinguished name in one certificate with the subject name in a CA certificate. Rules for comparing distinguished names are specified in Section 7.1." That said, we assess the risk to be low in this context, as the certificate must be signed by a trusted root certificate and SGX DCAP use cases are limited. As a result, it is unlikely that an attacker could successfully generate a PCK certificate with a colliding CN.

Open the report
LowInconsistent Expiration Validation Logic for `validityNotAfter`Datachain LCP-zkDCAP · Quantstamp · 8 Apr 2025Fixed

The logic used to validate the expiration of enclave keys in the `LCPClientZKDCAPBase.zkDCAPRegisterEnclaveKey()` function exhibits inconsistent behavior when `block.timestamp == output.validityNotAfter`. Specifically, the current implementation allows this edge case to pass when `key_expiration == 0`, but triggers a revert when `key_expiration != 0`. This inconsistency may lead to unexpected or confusing behavior for integrators or future auditors of the code. Although this is an edge case and would only cause a transient error, ensuring consistent validation logic is important for clarity and maintainability.

Open the report
LowMissing Strict Validation of Critical x.509 Certificate ExtensionsDatachain LCP-zkDCAP · Quantstamp · 8 Apr 2025Fixed

The current implementation of Intel SGX PCK certificate validation logic does not explicitly verify critical X.509 extensions such as `Key Usage` (OID: `2.5.29.15`) and `Basic Constraints` (OID: `2.5.29.19`). According to [RFC5280 section 4.2](https://datatracker.ietf.org/doc/html/rfc5280), a certificate-using system must reject a certificate if it encounters a critical extension it does not recognize or a critical extension that contains information it cannot process. According to the [Intel SGX PCK Certificate specification](https://api.trustedservices.intel.com/documents/Intel_SGX_PCK_Certificate_CRL_Spec-1.5.pdf), certificates have the following extensions marked as "critical": - **PCK Leaf Certificate**: `Key Usage` (`Digital Signature`, `Non Repudiation`), `Basic Constraints` (`CA:FALSE`). - **PCK Issuer CA Certificate**: `Key Usage` (`Certificate Sign`, `CRL Sign`), `Basic Constraints` (`CA:TRUE`, `pathlen:0`). - **Intel SGX Root CA Certificate**: `Key Usage` (`Certificate Sign`, `CRL Sign`), `Basic Constraints` (`CA:TRUE`, `pathlen:1`). - **TCB Singing Certificate**: `Key Usage` (`Digital Signature`, `Non Repudiation`), `Basic Constraints` (`CA:FALSE`). Failing to enforce these validations may allow certificates with inappropriate key usage or incorrect CA constraints, weakening the trustworthiness of the certificate chain.

Open the report
LowOverflow Risk in `collateral.rs`Datachain LCP-zkDCAP · Quantstamp · 8 Apr 2025Fixed

In the `collateral.rs::from_bytes()` function, the sum of the lengths could potentially overflow. Specifically, these values are read from the input `slice`, meaning they can be manipulated. If an overflow occurs, the `QvCollateral` structure could be re-constructed from unexpected bytes. Here is the code snippet where the overflow risk can occur: ```rust if slice.len() < offset + tcb_info_json_len + qe_identity_json_len + sgx_intel_root_ca_der_len + sgx_tcb_signing_der_len + sgx_intel_root_ca_crl_der_len + sgx_pck_crl_der_len { bail!("Invalid QvCollateral length"); } ```

Open the report
LowPotential Infinite Loop in `parse_x509_der_multi()`Datachain LCP-zkDCAP · Quantstamp · 8 Apr 2025Fixed

The `utils.rs::parse_x509_der_multi()` function contains a potential infinite loop vulnerability. When processing a sequence of X.509 certificates, the function iteratively calls `X509Certificate::from_der()` and updates the input slice `i` with the remaining bytes `j` returned by the parser. However, there is no check to ensure that the parser is making progress through the buffer. If the parser returns a non-empty slice (`j`) that is the same length as the input slice (`i`), the function will enter an infinite loop.

Open the report
LowUpgradeable Contracts Should Call `_disableInitializers()`Datachain LCP-zkDCAP · Quantstamp · 8 Apr 2025Fixed

The upgradeable contracts `LCPClientIASOwnableUpgradeable` and `LCPClientZKDCAPOwnableUpgradeable` allow an attacker to initialize the implementation contract, which could lead to phishing and social engineering attacks. For more details, see the [OpenZeppelin guideline](https://docs.openzeppelin.com/upgrades-plugins/writing-upgradeable#initializing_the_implementation_contract).

Open the report
LowArbitrage Is Only Prohibited For Negative Price DriftDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

The `getDriftProtocolFee()` is intended to eliminate any profits that might be made from token arbitrage. If `srcPrice < dstPrice`, it will charge the user any profits made from the arbitrage as a fee. Otherwise it will return a fee of zero. However, if the `srcStatus == IStableTokenPriceOracle.PriceDeviationStatus.Normal`, then a fee of zero is returned regardless of whether an arbitrage opportunity exists. If the `dstPrice` has an upwards depeg such that it is worth more than the pegged `srcPrice` (such as $1.01), then an arbitraged trade is possible. While price depegs in the upwards direction tend to repeg quickly, it is important to consider how rapid fluctuations in liquidity affect the protocol.

Open the report
LowEmpty `fallback()` Function in `BridgeFallback` Masks ErrorsDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

The `BridgeFallback` contract currently has an empty `fallback()` function. This implementation creates a security concern in the context of upgradeable contracts. When users interact with the `Bridge` contract using an outdated ABI after an upgrade, calls to functions that no longer exist or have changed signatures will be routed to the `fallback()` function. Because the `fallback()` function is empty, these calls will appear to succeed (they won't revert and will return no data).

Open the report
Show 10 more
LowInaccurate balance checkDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

As described by the delta algorithm, the `Pool.transfer()` function will check that there is sufficient balance in the destination pool before executing a transfer. However, the balance check does not match the balance decremented on receival: ``` // Pool.transfer() feeInfo.lastKnownBalance = amountGD - feeInfo.lpFee + feeInfo.eqReward; if (peerPoolInfo.balance < amountGD) { revert TokiInsufficientPoolLiquidity( peerPoolInfo.balance, amountGD ); } // Pool.recv() peerPoolInfo.lastKnownBalance = peerPoolInfo.lastKnownBalance - feeInfo.lastKnownBalance; ``` If `feeInfo.lpFee > feeInfo.eqReward`, it is possible that the transfer will overdraft and revert due to underflow on the receiving side, thereby breaking the guarantee of finality.

Open the report
LowLocked EtherDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

Empty `receive()` function can lead to permanently locked ETH in contract if users accidentally send ETH directly to the contract without using the intended functions.

Open the report
LowPrice Unit Inconsistency Risk in Token Price Oracle ImplementationDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

The current token price oracle implementation lacks validation for price units and decimals between different chains' native tokens. This could lead to incorrect fee calculations if the price feeds use inconsistent units or decimal places. ```solidity function _calcSrcNativeAmount( uint256 dstGas, uint256 dstTokenAmount, uint256 srcTokenPrice, // No unit validation uint256 dstTokenPrice, // No unit validation uint256 dstGasPrice, uint256 riskBPS ) internal pure returns (uint256) ``` This could result in incorrect fee calculations leading to under/over charging users and potential economic losses for users or relayers.

Open the report
LowUnable to Transfer ETH to PoolDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

The `Bridge.deposit()` contract is `payable`. However, the `IBCUtils.safeTransferFrom()` function does not support sending ETH. This prevents users from depositing ETH into the pool when calling `Bridge.deposit()` directly.

Open the report
LowUnbounded Loop in `_deltaSourceUpdate` Leads to Potential Denial-of-Service (Dos) AttackDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

The `_deltaSourceUpdate()` function in `Pool.sol` contains a loop that iterates over all entries in the `_peerPoolInfos` array. The number of iterations of this loop is not bounded by any constant or configuration parameter. If the number of peer pools grows large, this loop could consume excessive gas, potentially leading to out-of-gas errors and a denial-of-service (DoS) condition. **Specifically, the following loops are affected:** ```solidity for (uint256 i = 0; i < peerPoolInfosLength; ++i) { ... } ```

Open the report
LowUndisabled initializers within upgradeable contract implementationDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

The constructors of implementation contracts fail to call the `_disableInitializers()` function, leaving the contracts vulnerable to unexpected initialization outside the proxy.

Open the report
LowUnprotected `reinitializer` functionDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

The `RecoveredLCPClientUpgradeable.upgrade()` is an unprotected `reinitializer` function that can be exploited in protocol takeover scenarios.

Open the report
LowUsage of the transfer function can lead to unexpected future behaviorDatachain - App for Liquidity · Quantstamp · 27 Jan 2025Fixed

Relying on `address.transfer()` in Solidity for a reentrancy-free transfer of funds can lead to unexpected failed calls. The gas cost of different opcodes has been adjusted before and can be adjusted again, which may create unforeseen side effects.

Open the report
Low`Fraction` Instances Can Have Invalid RatiosDatachain - ELC for Bridge - Ethereum · Quantstamp · 8 Jan 2025Fixed

The `Fraction` struct consists of a `numerator` and a `denominator` and it doesn't currently perform any validation of the values when a new instance is created. The following fractions can be created without errors: - A fraction whose `numerator` is greater than its `denominator`; - A fraction whose `denominator` is zero. While it is in principle possible for a mathematical fraction to have a numerator that is greater than its denominator, such instances do not appear to fit the intended use case, i.e. representing the `trust_level` field in a `ClientState` instance.

Open the report
LowInconsistent State Id Generation Due to Unreset `frozen_height`Datachain - ELC for Bridge - Ethereum · Quantstamp · 8 Jan 2025Fixed

When canonicalizing the `ClientState` to generate a consistent `StateID`, the code resets `latest_execution_block_number` to zero. However, if `frozen_height` is set (i.e., not `None`), it remains unchanged. This can lead to different state IDs when they should be identical, causing unexpected inconsistencies in downstream logic that rely on stable identifiers.

Open the report
Show 10 more
LowNot Taking Update's Next Sync CommitteeDatachain - ELC for Bridge - Ethereum · Quantstamp · 8 Jan 2025Fixed

The function `apply_updates()` is designed to mirror the function of the spec named `apply_light_client_update()`. In the latter function, when the stored consensus state lacks a next sync committee, it is checked that the update's finalized header's sync committee period is equal to the stored consensus state's sync committee period, and the update's next sync committee is added to the stored consensus state. However, this assignment does not take place at any point in `apply_updates()`. However, this appears not to be a problematic issue as it appears that the stored consensus state will never be lacking a next sync committee. This is despite the fact that when the new consensus state is validated in `ConsensusState::validate()`, it is not checked whether there is a next sync committee.

Open the report
LowConsider Using `rand::rndg::OsRng` for More RobustnessDatachain - LCPs · Quantstamp · 9 Dec 2024Fixed

The function `get_quote()` in `ias_utils.rs` uses `rand::thread_rng()` which provides a pseudorandom value in each thread independently which might not be as robust or secure as desired.

Open the report
LowDependency RisksDatachain - LCPs · Quantstamp · 9 Dec 2024Fixed

The [Cargo audit](https://github.com/RustSec/rustsec/tree/main/cargo-audit) report has identified potential dependency risks. Here is a summary of the risks: **Key Vulnerabilities:** 1. **curve25519-dalek (v3.2.0)** - **Issue**: Timing variability in `Scalar29::sub` and `Scalar52::sub`. - **Solution**: Upgrade to version >= 4.1.3. - **Link**: [RUSTSEC-2024-0344](https://rustsec.org/advisories/RUSTSEC-2024-0344) 2. **ed25519-dalek (v1.0.1)** - **Issue**: Double Public Key Signing Function Oracle Attack. - **Solution**: Upgrade to version >= 2. - **Link**: [RUSTSEC-2022-0093](https://rustsec.org/advisories/RUSTSEC-2022-0093) 3. **h2 (v0.3.19)** - **Issue**: CONTINUATION Flood vulnerability causing service degradation. - **Solution**: Upgrade to ^0.3.26 or >= 0.4.4. - **Link**: [RUSTSEC-2024-0332](https://rustsec.org/advisories/RUSTSEC-2024-0332) 4. **libgit2-sys (v0.15.2)** - **Issue**: Memory corruption, denial of service, and arbitrary code execution. - **Solution**: Upgrade to version >= 0.16.2. - **Link**: [RUSTSEC-2024-0013](https://rustsec.org/advisories/RUSTSEC-2024-0013) 5. **rsa (v0.9.2)** - **Issue**: Timing side-channel vulnerability (Marvin Attack). - **Solution**: No available fix. - **Link**: [RUSTSEC-2023-0071](https://rustsec.org/advisories/RUSTSEC-2023-0071) 6. **rustls (v0.19.1 and v0.20.6)** - **Issue**: Infinite loop vulnerability in network input handling. - **Solution**: Upgrade to specific patched versions. - **Link**: [RUSTSEC-2024-0336](https://rustsec.org/advisories/RUSTSEC-2024-0336) 7. **shlex (v1.1.0)** - **Issue**: Quote API issues. - **Solution**: Upgrade to version >= 1.3.0. - **Link**: [RUSTSEC-2024-0006](https://rustsec.org/advisories/RUSTSEC-2024-0006) 8. **tungstenite (v0.17.3)** - **Issue**: Denial of service vulnerability. - **Solution**: Upgrade to version >= 0.20.1. - **Link**: [RUSTSEC-2023-0065](https://rustsec.org/advisories/RUSTSEC-2023-0065) 9. **webpki (v0.21.4)** - **Issue**: CPU exhaustion in certificate path building. - **Solution**: Upgrade to version >= 0.22.2. - **Link**: [RUSTSEC-2023-0052](https://rustsec.org/advisories/RUSTSEC-2023-0052) **Other Warnings:** 1. Unmaintained Crates: Several crates, including `atty`, `buf_redux`, `mach`, and `multipart`, are unmaintained and may need replacement. 2. Yanked Crates: Some crates, such as `futures-util` and `hermit-abi`, are marked as yanked. <br> **Additionally**, we have manually identified some outdated dependencies that can be upgraded: 1. The codebase is using the `tiny_keccak` library version 1.5, while the latest version is 2.0.2 ([crates.io](https://crates.io/crates/tiny-keccak)). 2. It is also using `sha2` version 0.10.6, while the latest is 0.10.8. 3. The API version used for the attestation mechanism is v4, while the latest is v5. We recommend addressing these vulnerabilities and updating the outdated dependencies to enhance the security and reliability of the project.

Open the report
LowEnclave Key Remains in Memory After UseDatachain - LCPs · Quantstamp · 9 Dec 2024Fixed

The enclave key currently remains in memory after it is unsealed and used. Since it represents the critical source of trust in the system, limiting its exposure to hardware level attacks is recommended.

Open the report
LowEnclave Leaking Panic ContentsDatachain - LCPs · Quantstamp · 9 Dec 2024Fixed

The panic handler added to this forked crate makes use of `ocall` to pass panic information outside of the enclave, simply forwarding the info associated with the panic.

Open the report
LowNot All Sequence Variables Are Stored in the Provable StoreDatachain - IBC · Quantstamp · 9 Dec 2024Fixed

The function `initializeSequences()` sets initial values in `channelStorage` for `nextSequenceSend`, `nextSequenceRecv`, and `nextSequenceAck`. However, only `nextSequenceRecv` is stored directly in the provable store: ``` getCommitments()[IBCCommitment.nextSequenceRecvCommitmentKey(portId, channelId)] = keccak256(abi.encodePacked((bytes8(uint64(1))))); ``` The [ICS-024 specification](https://github.com/cosmos/ibc/blob/47fea20d4d400e967721396092c6b43398c65d78/spec/core/ics-024-host-requirements/README.md#path-space) suggests that all three should be committed to the provable store.

Open the report
LowNot Returning Error or Reverting when Size OverflowsDatachain - LCPs · Quantstamp · 9 Dec 2024Fixed

The `calc_raw_sealed_data_size()` function returns `max` when there is an unexpected size. This is a copy of the implementation from the [sgx_tseal/src/internal.rs](https://github.com/apache/incubator-teaclave-sgx-sdk/blob/1b1d03376056321441ef99716aa0888bd5ef19f7/sgx_tseal/src/internal.rs#L97-L109). However, in the Rust SGX SDK, it will error out (see: [code](https://github.com/apache/incubator-teaclave-sgx-sdk/blob/1b1d03376056321441ef99716aa0888bd5ef19f7/sgx_tseal/src/internal.rs#L301)) at the place calling when receiving the `max` output. We suggest that the same should be applied here.

Open the report
LowPanic Due to Out-of-Boundary AccessDatachain - LCPs · Quantstamp · 9 Dec 2024Fixed

The `LCPUtils.readBytesUntil()` function calls the `BytesUtils.find()` function. The `BytesUtils.find()` function has the `len` input, which represents the number of bytes to search (see: [code comment](https://github.com/ensdomains/ens-contracts/blob/160919f5612e52347f016a537c6278ecc0f2325a/contracts/dnssec-oracle/BytesUtils.sol#L383)). The current implementation passes `src.length` as the `len` input, which will trigger a panic when the needle is not found, as it will attempt to search outside of `src.length`. There is no real impact feature-wise, as `readBytesUntil()` intends to revert with `LCPUtilsReadBytesUntilNotFound()` when the needle is not found. However, it might make it hard to identify the reason for a failed transaction.

Open the report
LowPotential Arbitrary Calls in `updateClient()`Datachain - IBC · Quantstamp · 9 Dec 2024Fixed

In `IBCClient.updateClient()`, there is the possibilitiy for a light client supporting arbitrary function calls, in the case where the call to `lc.routeUpdateClient()` were to return an unexpected function selector that would then be invoked on the Light Client itself. The Datachain team has already noted this situation in documentation ADR-001 however we include it here for clarity. There, they mention that this can be mitigated at the relayer level, by relayers including a whitelist of expected functions. Additionally, we trust that the light clients are implemented honestly to not support arbitrary calls.

Open the report
LowUsage of Unrecommended `parse_overflowing_slice()`Datachain - LCPs · Quantstamp · 9 Dec 2024Fixed

The `verify_signature()` function uses `Signature::parse_overflowing_slice()`, which is not recommended according to its [code comment](https://github.com/paritytech/libsecp256k1/blob/48dabd8821852c5fe00b846f6c37e1f6b05c3d8c/src/lib.rs#L558-L560). The code comment recommends using `parse_standard_slice()` instead.

Open the report
Show 5 more
LowValidator Does Not Check for Suggested Identifier Size RestrictionsDatachain - IBC · Quantstamp · 9 Dec 2024Fixed

The table in [ICS-024](https://github.com/cosmos/ibc/blob/47fea20d4d400e967721396092c6b43398c65d78/spec/core/ics-024-host-requirements/README.md#paths-identifiers-separators) suggests that a client identifier should be between 9-64 characters, however no such check occurs in `validateClientType()`. Note that `validatePortIdentifier()` does include checks for the suggested length.

Open the report
LowClient Can Be Initialized with Zero HeightDatachain - ELC For Bridge - BSC · Quantstamp · 6 Dec 2024Fixed

The current light client implementation is in violation of the [specification](https://github.com/datachainlab/parlia-elc/blob/main/SPEC.md#client-initialisation), which states that clients must be initialized only with heights greater than zero.

Open the report
LowCorrespondence Between `chain_id.version` and `latest_height.revision_number` Is Not Enforced, Potentially Violating StateID UniquenessDatachain - ELC For Bridge - BSC · Quantstamp · 6 Dec 2024Fixed

When a "State ID" is being generated from a client state and a consensus state, the client state is first simplified by calling `ClientState::canonicalize()`. This sets the `latest_height` to `{revision_number: self.chain_id.version, revision_height: 0}`. As such, there is an implicit correspondence between `chain_id.version` and `latest_height.revision_number`. However, no such correspondence is enforced when instantiating a `ClientState` (e.g. in `ClientState::try_from(value: RawClientState)`). Therefore, via data corruption, it is in principle possible for client states that are intended to refer to the same client state to be different via `chain_id.version`, and therefore result in different state IDs being generated for each.

Open the report
LowRevision Number Is Not Validated When Decoding Client StateDatachain - ELC For Bridge - BSC · Quantstamp · 6 Dec 2024Fixed

In communications with the client, it was determined that for any given `ClientState`, the `latest_height.revision_number` value should be equal to 0. However, when decoding a `RawClientState`, there is no validation indicating that a non-zero `revision_number` is forbidden. This may enable the use of invalid client states in the ELC.

Open the report
LowUnexpected Client Behaviour if Pre-Bohr Fork Blocks Are UsedDatachain - ELC For Bridge - BSC · Quantstamp · 6 Dec 2024Fixed

The current light client implementation is only compatible with blocks generated after the Bohr fork. In itself, this is merely an operational consideration as it represents the expectation of the developer. However, if a block height from before the Bohr fork is submitted, the client may behave unexpectedly because it lacks validation to prevent the submission of pre-Bohr fork blocks. The header parsing and BLS signature verification logic rely on the structure introduced in BEP-341 and BEP-402, which added fields like turn length data and modified signature verification processes. In BEP-341, the header's extra data field includes the turn length information, and the parsing logic accounts for this when extracting vote attestation data. Similarly, BEP-402 introduced changes to signature verification by adding new fields that must be verified. The parsing functions, such as `get_vote_attestation` and `get_validator_bytes_and_tern_term`, are designed to work with the modified header structure post-Bohr fork. When creating a client, it is assumed that the latest block height exceeds the Bohr fork height, but there is no explicit validation to enforce this. Submitting a block from before the Bohr fork can lead to parsing errors or unexpected client behaviour.

Open the report

Contracts

No deployed address is recorded for these audits.

The reports name a repository or files. Open a report to see its scope.

The repositories and files the reports name

Show this on your site

Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.

Content

Facts

Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-tb-project-slug="datachain"
></div>
</body>

Paste the code where the label should appear. It uses no API credit and updates by itself.

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us