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.
Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| Datachain - ELC for Bridge (OptimismELC) | Security firm: Quantstamp | Date: | Scope: Not recorded (see the report) | No open critical findings | Open · certificate.quantstamp.com |
| Datachain LCP-zkDCAP | Security firm: Quantstamp | Date: | Scope: Files named in the report | No open critical findings | Open · certificate.quantstamp.com |
| Datachain - App for Liquidity | Security firm: Quantstamp | Date: | Scope: Repository at commit dcccb98 | No open critical findings | Open · certificate.quantstamp.com |
| Datachain - ELC for Bridge - Ethereum | Security firm: Quantstamp | Date: | Scope: Repository at commit 7a40e6a | No open critical findings | Open · certificate.quantstamp.com |
| Datachain - IBC | Security firm: Quantstamp | Date: | Scope: Repository at commit ca7a56c | No open critical findings | Open · certificate.quantstamp.com |
| Datachain - LCPs | Security firm: Quantstamp | Date: | Scope: Repository at commit 54d2bac | No open critical findings | Open · certificate.quantstamp.com |
| Datachain - ELC For Bridge - BSC | Security firm: Quantstamp | Date: | Scope: Repository at commit 78d1349 | No open critical findings | Open · certificate.quantstamp.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 1 | 7 |
| Medium | 1 | 1 | 7 |
| Low | 0 | 7 | 41 |
`_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 reportThe 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`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 reportIn 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 reportDuring 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`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 reportThe 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 reportIn 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 reportWhen 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 reportThe `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 reportThe `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 reportAs 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 reportA 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 reportSuppose 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 reportThe `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 reportThe `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 reportThe `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 reportValidation 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 reportThe `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 reportThe `update_client()` function has a `todo!()` for `ClientMessage::Misbehaviour`. Hence, the light client cannot currently process or react to misbehaviour reports.
Open the reportThe 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 reportCurrently, 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 reportThe `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 reportThe 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 reportThe 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 reportIn 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 reportThe `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 reportThe 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 reportThe `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 reportThe `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 reportAs 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 reportEmpty `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 reportThe 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 reportThe `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 reportThe `_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 reportThe constructors of implementation contracts fail to call the `_disableInitializers()` function, leaving the contracts vulnerable to unexpected initialization outside the proxy.
Open the reportThe `RecoveredLCPClientUpgradeable.upgrade()` is an unprotected `reinitializer` function that can be exploited in protocol takeover scenarios.
Open the reportRelying 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 reportThe `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 reportWhen 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 reportThe 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 reportThe 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 reportThe [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 reportThe 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 reportThe 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 reportThe 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 reportThe `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 reportThe `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 reportIn `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 reportThe `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 reportThe 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 reportThe 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 reportWhen 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 reportIn 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 reportThe 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 reportThe reports name a repository or files. Open a report to see its scope.
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.
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.
<head><script src="https://widget.trustblock.run/project-widget.min.js" defer></script></head><body><divdata-tb-project-widgetdata-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