Building on Avalanche? Ava Labs can cover up to 75% of your audit, and we take 10% off our quote. Avalanche audits: up to 75% covered. See how

Work & reportsReport

Jump DeFiBackend & Frontend Security Assessment

Guvenkaya reviewed the Jump DeFi backend services, indexers and web frontend.

Jump DeFi logo

Date of engagement: 10th December 2024 - 6th January 2025

  • Timur GüvenkayaPrincipal advisor

Engagement Dashboard

Audit results

Guvenkaya conducted a security assessment of the Jump Defi backend and Jump Defi frontend from 10th December 2024 to 6th January 2025. During this engagement, a total of 13 findings were reported. 8 of the findings were critical, 1 high, 3 medium, and 1 low severity. All major issues were fixed by the Jump Defi team.

Engagement record

Client
Jump Defi
System
Jump DeFi backend and web frontend
Review period
10th December 2024 - 6th January 2025
Paths in scope
7
Principal advisor
Timur Güvenkaya

Timeline

  1. Review start10th December 2024
  2. Draft report6th January 2025
  3. Final report18th January 2025

Findings by severity

  • Critical 8
  • High 1
  • Medium 3
  • Low 1
  • Informational 0

Finding status at final report

13Raised
12Fixed
1Acknowledged

Remediation complexity

11Simple
2Moderate

Impact

8Severe
4Moderate
1Negligible

Likelihood

10Likely
1Possible
2Rare

Advisory and Client

The advisory

Guvenkaya specializes in security for digital assets and financial infrastructure, from smart contracts and protocols to applications, infrastructure, custody and cryptography.

Our team, including the sitting Heads of Security at Gauntlet and Agora, brings experience from Kraken, OpenZeppelin, Binance, ZKsync, Nillion, Invicti and EY. Across the team: 200+ security reviews, $30B+ in volume secured, 13 published cryptography research papers, and credentials including OSCP, OSWE and CISM.

  • Every reviewer has a public bio and is named before you sign. We match expertise to your system, with a principal leading scoping and checking findings.

The client

Jump Defi is the only one-stop decentralized finance platform on NEAR Protocol. Jump DeFi lowers the barrier of entry to decentralized finance for users and developers.

Scope and Review Boundaries

Review depths

Deep
Line-by-line review with explicit attack hypotheses, adversarial reasoning about state transitions, and reproduction attempts for each hypothesis that survived reading.
Supporting
The code was read for its effect on a reviewed flow. Behaviour outside that effect was not assessed.
Targeted
Entry points were exercised or triaged against the flow's security properties rather than read in full.

This is the code we read, and how closely. 7 paths are in scope. Each path links to the file at the reviewed commit.

PathReview depthScope note
indexer-helperDeepIndexer Helper (Excluding Backend Deployment Scripts)
cacheDeepCache
aggregatorDeepAggregator
amm-indexerDeepAMM Indexer
indexerDeepIndexer
near_serviceDeepNEAR Service
packages/webDeepWeb Package (Excluding tests and assets)

Out of scope

The audit will include reviewing the code for security vulnerabilities. The audit does not include a review of the tests and dependencies.

Assessment Framework

Guvenkaya rates findings by likelihood and impact so remediation can be prioritized by technical risk, business context, and the decision the engagement is meant to support.

Rating chain applied to every finding

  1. 01 Likelihood Likely, possible or rare
  2. 02 Impact Severe, moderate or negligible
  3. 03 Severity Derived from the matrix below
  4. 04 Remediation complexity Simple, moderate or difficult
  5. 05 Status Not fixed, fixed, acknowledged or scheduled

Impact

ImpactWhat it means here
SevereExploitation could result in critical loss or compromise, such as full system control, substantial financial loss, or severe reputational damage.
ModerateExploitation may lead to limited data loss, partial compromise, moderate financial impact, or noticeable degradation of services.
NegligibleExploitation has minimal impact, such as minor data exposure without significant consequences or slight inconvenience without substantial disruption.

Likelihood

LikelihoodWhat it means here
LikelyThe vulnerability is easily discoverable and not overly complex to exploit.
PossibleThe vulnerability presents some challenges either in discovery or in the complexity of the attack.
RareThe vulnerability is either very difficult to discover or complex to exploit, or both.

This matrix provides a nuanced view, taking into account both the ease of discovering a vulnerability and the complexity involved in exploiting it.

Attack Complexity \ Discovery EaseObviousConcealedHidden
ComplexPossibleRareRare
ModerateLikelyPossibleRare
StraightforwardLikelyPossiblePossible

Severity

SeverityWhat it means here
CriticalAssigned to vulnerabilities with severe impact and a likely likelihood of exploitation.
HighFor vulnerabilities with either severe impact but only a possible likelihood, or moderate impact with a likely likelihood.
MediumUsed for vulnerabilities with severe impact but a rare likelihood, moderate impact with a possible likelihood, or negligible impact with a likely likelihood.
LowFor vulnerabilities with moderate impact and rare likelihood, or negligible impact with a possible likelihood.
InformationalThe lowest severity rating, typically for vulnerabilities with negligible impact and a rare likelihood of exploitation.
Likelihood \ ImpactSevereModerateNegligible
LikelyCriticalHighMedium
PossibleHighMediumLow
RareMediumLowInformational

Remediation complexity

This measures how difficult it is to remediate a finding once it has been identified.

Remediation complexityWhat it means here
SimplePatches or fixes are readily available and easily implemented.
ModerateRequires some time and resources to remediate, but well within the capabilities of most organizations.
DifficultRemediation requires significant resources, specialized skills, or substantial changes to systems or architecture.

Finding status

This tracks the client's response to each finding and whether remediation has been completed, accepted, or scheduled.

StatusWhat it means here
Not FixedIndicates that the vulnerability has been identified but no remedial action has been taken yet. This status is crucial for newly discovered vulnerabilities or those awaiting prioritization.
FixedThis status is applied when the vulnerability has been successfully remediated. It implies that appropriate measures, such as patching, configuration changes, or architectural modifications, have been implemented to resolve the issue.
AcknowledgedThis status is used for vulnerabilities that have been recognized, but for various reasons (such as risk acceptance, cost, or other business decisions), have not been fixed. It indicates that the risk posed by the vulnerability is known and has been consciously accepted.
ScheduledThis status indicates that the vulnerability has been acknowledged and a plan is in place to fix it in the future. It signifies that while remediation hasn't yet occurred, the issue has been prioritized and is part of the planned development roadmap.

Findings Summary

13All findings
8 Critical
1 High
3 Medium
1 Low
0 Informational

Findings register

FindingImpactLikelihoodSeverityRemediation complexityStatus
GUV-1: Indexer Crash Due to Invalid UTF-8 CharacterSevereLikelyCriticalSimpleFixed
GUV-2: Indexer Crash Due To Invalid Message FormatSevereLikelyCriticalSimpleFixed
GUV-3: Aggregator Crash Due To Not Matching PoolSevereLikelyCriticalSimpleFixed
GUV-4: Indexer Crash Due to Invalid Argument FormatsSevereLikelyCriticalSimpleFixed
GUV-5: Aggregator Crash Due To Integer OverflowSevereLikelyCriticalSimpleFixed
GUV-6: SQL Injection in User Wallet AdditionSevereLikelyCriticalSimpleFixed
GUV-7: SQL Injection In Liquidation Result AddingSevereLikelyCriticalSimpleFixed
GUV-8: Indexer Denial Of Service Due To Exceesive Number Of MessagesModerateLikelyCriticalSimpleFixed
GUV-9: Artificial Data Can Be Added Through AMM-IndexerModerateLikelyHighSimpleFixed
GUV-10: Any Pool Can Be Marked As Blacklisted On AggregatorNegligibleLikelyMediumSimpleFixed
GUV-11: Missing Tests Across The SystemModeratePossibleMediumModerateAcknowledged
GUV-12: Error-Prone Parsing of Liquidity PoolsSevereRareMediumModerateFixed
GUV-13: Usage of Panic Macro in Production CodeModerateRareLowSimpleFixed

Detailed Findings

GUV-1: Indexer Crash Due to Invalid UTF-8 Character

Severity
Critical
Impact
Severe
Likelihood
Likely
Remediation Complexity
Simple
Status
Fixed

Description

The Indexer uses String::from_utf8 to convert base64-decoded argument bytes to strings. However, it lacks proper error handlingand instead uses unwrap(), which causes a panic on None and Error results. The indexer also fails to verify whether transactions sent to valid addresses are successful.

indexer:handle_message:indexer/src/chains/near/stream.rs
let keywords = [        self.config.ref_finance_contract_id.clone(),        self.config.veax_contract_id.clone(),        self.config.jump_contract_id.clone(),    ];    let contains_keyword = keywords.contains(&receiver_id);    if contains_keyword {        let r = receipt.receipt;        if let ReceiptEnumView::Action { actions, .. } = &r {            for action in actions {                if let ActionView::FunctionCall { method_name, args, .. } = action {                    let args_base64: String = serde_json::from_value(serde_json::to_value(args).unwrap()).unwrap();                    let decoded_args = STANDARD.decode(args_base64).unwrap();                    let decoded_str = String::from_utf8(decoded_args).unwrap();                    let mut decoded_json: Value = serde_json::from_str(&decoded_str).unwrap();}

The root causes:

  • The indexer does not verify transaction success
  • The indexer uses unwrap() instead of proper error handling, causing panic on None/Error results

This vulnerability enables:

  • A malicious actor to crash the indexer with a single transaction

PoC

  • Compile the indexer in release mode and launch it
  • Send a transaction to any valid contract address with an argument containing a non-UTF8 character. The transaction does not need to execute successfully
  • Example: near contract call-function as-transaction ref-finance-101.testnet ft_transfer_call json- args "{"msg": "жжж"} prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as attacker.testnet network-config testnet sign-with-keychain send

Recommendation

  • Verify that transactions are successful
  • Implement proper error handling for all Option/Result values

Remediation

The Jump Defi team has fixed the issue by verifying the success of the receipt and replaced unwrap() with proper error handling

GUV-2: Indexer Crash Due To Invalid Message Format

Severity
Critical
Impact
Severe
Likelihood
Likely
Remediation Complexity
Simple
Status
Fixed

Description

The Indexer attempts to parse the msg argument from JSON into an array for ft_on_transfer transactions sent to the VEAXaddress. The issue arises from using unwrap() after .as_array() without proper error handling. The indexer also fails to verify transaction success.

indexer:handle_message:indexer/src/chains/near/stream.rs
    if !self.config.exclude_veax && receiver_id == self.config.veax_contract_id&& method_name == "ft_on_transfer"&& !decoded_json["msg"].as_str().unwrap_or("").is_empty() {    // msg contain stringify value, need to convert it to JSON    let msg_json = serde_json::from_str(        decoded_json["msg"].as_str().unwrap()    ).unwrap();    decoded_json["msgs"] = msg_json;     for msg in decoded_json["msgs"].as_array().unwrap() {        if let Some(obj) = msg.as_object() {            if obj.contains_key("OpenPosition") {                tracing::info!("stream::handle_message() Handling Veax OpenPosition Action");

The root causes:

  • The indexer does not verify transaction success
  • The indexer uses unwrap() instead of proper error handling, causing panic on None/Error results

This vulnerability enables:

  • A malicious actor to crash the indexer with a single transaction

PoC

  • Compile the indexer in release mode and launch it
  • Send a transaction to VEAX contract address with the msg argument containing a non-array value. The transaction does not need to execute successfully
  • Example: near contract call-function as-transaction veax-dex15.testnett ft_on_transfer json- args{"msg":"hak"} prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as attacker.testnet network-config testnet sign-with-keychain send

Recommendation

  • Verify that transactions are successful
  • Implement proper error handling for all Option/Result values

Remediation

The Jump Defi team has fixed the issue by verifying the success of the receipt and replaced unwrap() with proper error handling

GUV-3: Aggregator Crash Due To Not Matching Pool

Severity
Critical
Impact
Severe
Likelihood
Likely
Remediation Complexity
Simple
Status
Fixed

Description

The aggregator computes routes that are sent to the smart router contract. A mock router creation route ("/route/mock") is exposed in production without access control. Its create_route function attempts to fetch decimals for token_in and token_out by iterating over pools, but it uses .expect() instead of proper error handling.

aggregator:create_mock_route:aggregator/src/services/route_mock.rs
    if let Some(pools) = mock_pools.clone() {token_in_decimals = pools    .iter()    .find_map(|pool| {        if pool.token_in == token_in {            Some(pool.token_in_decimals)        } else if pool.token_out == token_in {            Some(pool.token_out_decimals)        } else {            None        }    })    .expect("No matching pool found for token_in"); token_out_decimals = pools    .iter()    .find_map(|pool| {        if pool.token_in == token_out {            Some(pool.token_in_decimals)        } else if pool.token_out == token_out {            Some(pool.token_out_decimals)        } else {            None        }    })    .expect("No matching pool found for token_out");

The root causes:

  • The aggregator has exposed test route in production
  • The aggregator uses .expect() instead of proper error handling, causing panics on None/Error results

This vulnerability enables:

  • A malicious actor to crash the aggregator with a single request

PoC

  • Compile the aggregator in release mode and launch it
  • Send the request to the /route/mock with token_in and/or token_out which do not match any of the pools:
Example request
curl -X POST 'http://127.0.0.1:8000/route/mock' -H 'Content-Type: application/json'             -d '{    "token_in": "token121.near",    "token_out": "token212.near",    "amount": 1000.0, "slippage": "0.5",    "providers": null, "pools": [{        "kind": "STABLE_SWAP", "liquidity_provider": "RefFinance",        "amp": 100, "key": "pool_key_1",        "pool_id": 1, "token_in": "token1.near",        "token_out": "token2.near", "reserves_in": "1000000",        "reserves_out": "1000000", "fees": null,        "fee_divisor": null, "liquidities": ["1000000", "1000000"],        "prices": null, "spot_prices": null,        "symbols": ["TOKEN1", "TOKEN2"], "token_in_decimals": 18,        "token_out_decimals": 18, "amounts": ["1000000", "1000000"],        "token_account_ids": ["token1.near", "token2.near"],        "decimals": [18, 18], "swap_path": {            "token_in": "token1.near", "token_out": "token2.near",            "amount_in": "1000", "amount_out": "995",            "internal_swap": null, "actual_order_book": null,            "calculated_order_book": null, "order_type": null,            "order_quantity": null,"slippage_tolerance_bp": null        }    }]}'

Recommendation

  • Remove the mock route from production code by utilizing test config
  • Implement proper error handling for all Option/Result values

Remediation

The Jump Defi team has fixed the issue by removing the mock route.

GUV-4: Indexer Crash Due to Invalid Argument Formats

Severity
Critical
Impact
Severe
Likelihood
Likely
Remediation Complexity
Simple
Status
Fixed

Description

For each supported method, the Indexer attempts to parse arguments from JSON into their respective types. The issue stems from using unwrap() without proper error handling. Additionally, the indexer fails to verify transaction success.

indexer:handle_message:indexer/src/chains/near/stream.rs
if ["ft_transfer_call"].contains(&method_name.as_str()) {     if !decoded_json["msg"].as_str().unwrap_or("").is_empty() {        let msg_json = serde_json::from_str(            decoded_json["msg"].as_str().unwrap()        ).unwrap();         decoded_json["msg"] = msg_json;         let ft_transfer_call: FtTransferCall = from_value(decoded_json.clone()).unwrap();        actions = ft_transfer_call.msg.actions;    }}...if method_name == "add_liquidity" { let add_liquidity: AddLiquidity =    from_value(decoded_json.clone()).unwrap();...}...if method_name == "remove_liquidity" { let remove_liquidity: RemoveLiquidity =    from_value(decoded_json.clone()).unwrap();...}             if method_name == "add_stable_liquidity" {            tracing::info!(            "stream::handle_message() Handling {} method",                    method_name              );
indexer:handle_message:indexer/src/chains/near/stream.rs (continued)
            let add_stable_liquidity: AddStableLiquidity =                from_value(decoded_json.clone()).unwrap();...for msg in decoded_json["msgs"].as_array().unwrap() {    if let Some(obj) = msg.as_object() {        if obj.contains_key("OpenPosition") {            tracing::info!(                "stream::handle_message() Handling Veax OpenPosition Action"            );            let open_position: OpenPosition =                from_value(msg["OpenPosition"].clone()).unwrap();

The affected methods include:

  • ft_transfer_call ⇒ FtTransferCall type
  • add_liquidity ⇒ AddLiquidity
  • remove_liquidity ⇒ RemoveLiquidity
  • add_stable_liquidity ⇒ AddStableLiquidity
  • ft_on_transfer (VEAX) ⇒ OpenPosition

The root causes:

  • The indexer does not verify transaction success
  • The indexer uses unwrap() instead of proper error handling

PoC

  • Compile the indexer in release mode and launch it
  • Send a transaction to any valid contract address with supported method and an argument which does not match the type expected by the method
  • Example: near contract call-function as-transaction ref-finance-101.testnet remove_liquidity json- args '"something":33' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as attacker.testnet network-config testnet sign-with-keychain send

Recommendation

  • Verify that transactions are successful
  • Implement proper error handling for all Option/Result values

Remediation

The Jump Defi team has fixed the issue by verifying the success of the receipt and replaced unwrap() with proper error handling

GUV-5: Aggregator Crash Due To Integer Overflow

Severity
Critical
Impact
Severe
Likelihood
Likely
Remediation Complexity
Simple
Status
Fixed

Description

The Aggregator allows users to calculate routes by accepting various arguments, including the amount parameter. The core issue lies in the use of unchecked mathematics operations throughout the codebase.

aggregator:get_amounts_distribution:aggregator/src/services/route.rs
fn get_amounts_distribution(amount: u128, distribution_percentage: u128) -> (Vec<u128>, Vec<u128>) {    tracing::info!("router::get_amounts_distribution() getting amounts distribution...");     let mut amounts: Vec<u128> = Vec::new();    let mut percents: Vec<u128> = Vec::new();     let iterations = (100u128 / distribution_percentage) as usize;     for i in 1..=iterations {        let percent = distribution_percentage * i as u128;        let amount = amount * percent / 100u128;         percents.push(percent);        amounts.push(amount);    }     (amounts, percents)}

The root cause:

  • The aggregator uses unchecked maths throughout the code

PoC

  • Compile the aggregator in release mode and launch it
  • Send the request to the /route with amount which equals to the u128::MAX
Example request
curl -X POST http://127.0.0.1:8000/route -H "Content-Type: application/json" -d               '{    "token_out": "usdt.tether-token.near",    "token_in": "wrap.near",    "amount": 340282366920938463463374607431768211455,    "slippage": "0.5",    "providers": ["Jump", "RefFinance"]}'

Recommendation

Utilize checked maths throughout the aggregator

Remediation

The Jump Defi team has fixed the issue by utilizing the checked maths.

GUV-6: SQL Injection in User Wallet Addition

Severity
Critical
Impact
Severe
Likelihood
Likely
Remediation Complexity
Simple
Status
Fixed

Description

The indexer helper exposes an endpoint for adding user wallets to the database via /add-user- wallet. The endpoint lacks verification of provided arguments before constructing SQL queries. Both account_id and wallet_address parameters are directly concatenated into the query string.

indexer_helper:add_user_wallet_info:indexer-helper/db_provider.py
query_sql = "select id from t_user_wallet_info where account_id = '%s' and wallet_address = '%s'" % (account_id, wallet_address)sql = "insert into t_user_wallet_info(account_id, wallet_address, `created_time`, `updated_time`) " \      "values('%s','','b','c'%s', now(), now())" % (account_id, wallet_address)cursor = db_conn.cursor()try:    cursor.execute(query_sql)    row = cursor.fetchone()     if row is None:        cursor.execute(sql)        db_conn.commit()except Exception as e:    db_conn.rollback()    print("insert t_user_wallet_info to db error:", e)    raise e

The root causes:

  • Missing access control on /add-user-wallet endpoint
  • Missing validation of user-provided arguments

This vulnerability enables a malicious actor to perform SQL injection attacks that can:

  • Read unauthorized data from the database
  • Insert malicious data into the database
  • Cause denial of service on the database
  • Potentially execute arbitrary code remotely

PoC

  • Launch indexer helper
  • Send request to /add-wallet-connection with Sleep command
Example request
curl -X POST "http://localhost:9000/add-user-wallet" -H "Content-Type: application/json" -d '{                            "account_id": "test_account3333",                            "wallet_address": "' UNION SELECT 1 AND SLEEP(20) -- "                        }'

Recommendation

  • Add access control to the add-user-wallet endpoint
  • Provide named parameters in .execute to prevent SQL injection

Remediation

The Jump Defi team has fixed the issue by removing the add-user-wallet endpoint.

GUV-7: SQL Injection In Liquidation Result Adding

Severity
Critical
Impact
Severe
Likelihood
Likely
Remediation Complexity
Simple
Status
Fixed

Description

The indexer helper exposes an endpoint for adding liquidation result to the database via /add- liquidation-result. The endpoint lacks verification of provided arguments before constructing SQL queries. Both key and values parameters are directly concatenated into the query string.

indexer_helper:add_liquidation_result:indexer-helper/db_provider.py
sql = "insert into liquidation_result_info(`key`, `values`, `timestamp`, `created_time`, `updated_time`) " \      "values('%s','%s',%s, now(), now())" % (key, values, now_time)cursor = db_conn.cursor(cursor=pymysql.cursors.DictCursor)try:    cursor.execute(sql)    db_conn.commit()

The root causes:

  • Missing access control on /add-liquidation-result endpoint
  • Missing validation of user-provided arguments

This vulnerability enables a malicious actor to perform SQL injection attacks that can:

  • Read unauthorized data from the database
  • Insert malicious data into the database
  • Cause denial of service on the database
  • Potentially execute arbitrary code remotely

PoC

  • Launch indexer helper
  • Send request to /add-liquidation-result with Sleep command
Example request
curl -X POST "http://localhost:9000/add-liquidation-result" -H "Content-Type: application/json" -d '{    "key": "pwned','pwned632622',(SELECT SLEEP(50)),'2023-01-01','2023-01-01')-- ",    "values": "1"}'

Recommendation

  • Add access control to the add-liquidation-result endpoint
  • Provide named parameters in .execute to prevent SQL injection

Remediation

The Jump Defi team has fixed the issue by removing the add-liquidation-result endpoint.

GUV-8: Indexer Denial Of Service Due To Exceesive Number Of Messages

Severity
Critical
Impact
Moderate
Likelihood
Likely
Remediation Complexity
Simple
Status
Fixed

Description

The Indexer iterates over a messages array to process individual messages. Since it verifies neither the number of messages nor the success of the receipt, an attacker can force the indexer to process a call containing an excessive number of messages. This prevents the indexer from processing any other blocks until it completes the current messages, resulting in a denial of service.

indexer:handle_message:indexer/src/chains/near/stream.rs
for msg in decoded_json["msgs"].as_array().unwrap() {    if let Some(obj) = msg.as_object() {        if obj.contains_key("OpenPosition") {            tracing::info!("stream::handle_message() Handling Veax OpenPosition Action");

The root cause:

  • The indexer does not verify transaction success

This vulnerability enables:

  • A malicious actor to cause denial of service of the indexer

PoC

  • Compile the indexer in release mode and launch it
  • Send a transaction to VEAX contract address with the msg argument containing a large number of entries

Example exploit code:

exploit
import json def generate_open_position(index):    return {        "OpenPosition": {            "fee_rate": 30,            "position": {                "amount_ranges": [{                    "max": "1000000000",                    "min": "100000000"                }],                "ticks_range": [100 + index, 200 + index]            },            "tokens": [f"token{index}a.testnet", f"token{index}b.testnet"]        }    } # Generate array with 100 messagesmessages = [generate_open_position(i) for i in range(100)] # Create the full payloadpayload = {    "sender_id": "malicious_acc.testnet",    "amount": "1000000000",    "msg": json.dumps(messages)} # Write the command to a file            command = f"""near contract call-function as-transaction veax-dex15.testnet ft_on_transfer json-args '{json.dumps(payload)}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as malicious_acc.testnet network-config testnet sign-with-keychain send"""             with open("run_attack.sh", "w") as f:                f.write(command)             print("Command written to run_attack.sh")             # Also print just the messages array for inspection            print("Messages array (first 2 for verification):")            print(json.dumps(messages[:2], indent=2))

Recommendation

Verify that transactions are successful

Remediation

The Jump Defi team has fixed the issue by verifying the success of the receipt.

GUV-9: Artificial Data Can Be Added Through AMM-Indexer

Severity
High
Impact
Moderate
Likelihood
Likely
Remediation Complexity
Simple
Status
Fixed

Description

The AMM indexer saves transaction data to the database based on the method called. Due to missing transaction validation, malicious users can insert artificial or incorrect data into the database.

Validation Issues per supported method:

  • ft_transfer_call | add_liquidity | remove_liquidity ⇒ No validation of transaction success, allowing anyone to update pool data and add transactions to the database
  • swap ⇒ No validation of transaction success, allowing anyone to add transactions to the database
  • add_simple_pool ⇒ Has transaction success validation, but the receiver ID check can be bypassed
amm_indexer:handle_streamer_message:amm-indexer/src/main.rs
if receiver_id.contains("jump_amm.testnet") {    let timestamp = streamer_message.block.header.timestamp_nanosec;    let signer_id = receipt.predecessor_id.to_string();    let receipt_id = receipt.receipt_id.to_string();

An attacker can:

  • Create an account such as jump_amm.testnet.attackerjump.testnet, which will bypass this check
  • Deploy smart contract with the function add_simple_pool which returns success
  • Call jump_amm.testnet.attackerjump.testnet with any add_simple_pool arguments to save the data to the indexer database

This vulnerability enables:

  • Bloating the database to make it costly to run and query
  • Causing system components to operate on invalid data

Recommendation

Transaction success must be verified, and exact equality should be used instead of contains() when matching supported contracts

Remediation

The Jump Defi team has fixed the issue by verifying the success of the receipt and replaced the contains() with exact equality.

GUV-10: Any Pool Can Be Marked As Blacklisted On Aggregator

Severity
Medium
Impact
Negligible
Likelihood
Likely
Remediation Complexity
Simple
Status
Fixed

Description

The Aggregator's /pool route allows pools to be blacklisted without any access control mechanism.

aggregator:update_pool:aggregator/src/main.rs
    #[put("/pool")]async fn update_pool(payload: web::Json<BlacklistPool>) -> impl Responder {    let BlacklistPool {        pool_id,        liquidity_provider,        token_in,        token_out,        blacklisted,    } = payload.into_inner();    tracing::info!(        "main::blacklist_pool() - Updating pool with pool_id: {}, blacklisted: {}",        pool_id,        blacklisted    );     let key = format!(        "pool:{}:{}:{}:{}",        liquidity_provider, pool_id, token_in, token_out    );     match pool::update_pool(&key, blacklisted)

Recommendation

Implement access control for this route

Remediation

The Jump Defi team has fixed the issue by removing the pool endpoint.

GUV-11: Missing Tests Across The System

Severity
Medium
Impact
Moderate
Likelihood
Possible
Remediation Complexity
Moderate
Status
Acknowledged

Description

The system components lack test coverage. Given the numerous cases and complex calculations performed by the indexers and aggregator, comprehensive test coverage is essential.

Recommendation

Write both unit and integration tests for indexer, amm-indexer, and aggregator

Remediation

The Jump Defi team has acknowledged the issue and will fix it later.

GUV-12: Error-Prone Parsing of Liquidity Pools

Severity
Medium
Impact
Severe
Likelihood
Rare
Remediation Complexity
Moderate
Status
Fixed

Description

The parse_liquidity_pools function relies on array indexes to extract data from bulk_data. This approach is error-prone as changes to data format or missing fields will cause crashes. The function's validation is also incorrect - it checks if bulk_data.len() >= 8, but accesses index 43.

cache:parse_liquidity_pools:cache/src/services/parser.rs
if let Value::Bulk(bulk_data) = value {    // Extract required data from bulk data    if bulk_data.len() >= 8 {        let pool_id = get_value_as_string(&bulk_data[1]);        let liquidity_provider = get_value_as_string(&bulk_data[3]);        let token_in: String = get_value_as_string(&bulk_data[5]);        ...        let chain_id = get_value_as_string(&bulk_data[43]);

Recommendation

  • Do not rely on indexes to fetch data from Redis
  • Implement a proper deserializer using FromRedisValue trait for the expected type

Remediation

The Jump Defi team has fixed the issue by rewriting the logic to parse the bulk data without relying on indexes.

GUV-13: Usage of Panic Macro in Production Code

Severity
Low
Impact
Moderate
Likelihood
Rare
Remediation Complexity
Simple
Status
Fixed

Description

The divide_and_floor function uses the panic! macro when encountering a zero divisor. Although this function is currently unused in the main codebase, it should be removed to prevent potential crashes if implemented in the future.

aggregator:divide_and_floor:aggregator/src/services/pool.rs
fn divide_and_floor(&self, dividend: BigUint, divisor: BigUint) -> BigUint {                if divisor.is_zero() {                    panic!("Division by zero");                }                dividend / divisor // In BigUint, division is inherently floor division            }

Recommendation

Remove divide_and_floor function

Remediation

The Jump Defi team has fixed the issue by removing the divide_and_floor function.

The web version and the PDF (25 pages) are generated from the same source. The report as first delivered is kept in the public reports archive.

Tell us what you need to secure.

Describe your system, main concern, and deadline. We’ll reply with scoping questions and a proposed next step.

Discuss your scope