QuantAMM

QuantAMM
49,600 OP
View results
Submission Details
Severity: low
Invalid

Lack of Input Validation in Factory Allows Attackers to Create Malicious Pools Leading to Potential Exploits

Summary:

The QuantAMMWeightedPoolFactory does not perform sufficient input validation on critical parameters provided for pool creation, such as normalizedWeights, tokens, and poolRegistry. This lack of validation can be exploited by attackers to create malicious pools with invalid configurations, enabling attacks such as fund theft, denial of service, or manipulation of swap calculations. Users interacting with such pools may suffer financial losses, and the integrity of the protocol could be compromised.


Root Cause:

The factory's create function accepts user-provided parameters without thorough validation. Critical parameters like normalizedWeights and token addresses are accepted as-is, allowing an attacker to deploy a pool with configurations that violate the protocol's assumptions or expose vulnerabilities.

Vulnerable Code:

In QuantAMMWeightedPoolFactory.sol:

function create(NewPoolParams memory params) external returns (address pool, bytes memory poolArgs) {
// No validation on params.normalizedWeights, params.tokens, params.poolRegistry, etc.
// ...
pool = _create(poolArgs, params.salt);
QuantAMMWeightedPool(pool).initialize(
params._initialWeights,
params._poolSettings,
params._initialMovingAverages,
params._initialIntermediateValues,
params._oracleStalenessThreshold
);
_registerPoolWithVault(
pool,
params.tokens,
params.swapFeePercentage,
false, // not exempt from protocol fees
params.roleAccounts,
params.poolHooksContract,
liquidityManagement
);
}

Attack Path:

  1. Attacker Deploys Malicious Pool:

    • The attacker calls the create function to deploy a new pool.

    • They provide manipulated parameters, such as normalizedWeights that do not sum to 1e18, invalid or malicious tokens, and improper poolRegistry settings.

  2. Malformed Pool Created:

    • Due to lack of validation, the factory creates the pool with the attacker's parameters.

    • The pool is registered with the Balancer Vault, and appears as a legitimate pool to users.

  3. Exploitation Scenarios:

    • Scenario 1: Malicious Tokens

      • The attacker uses tokens that have backdoors or do not conform to the ERC20 standard.

      • When users interact with the pool, these tokens may execute malicious code, leading to fund theft or other attacks.

    • Scenario 2: Incorrect Weights

      • Weights do not sum to 1e18, causing miscalculations in swap and liquidity provision functions.

      • The attacker manipulates weights to favor themselves in swaps, extracting disproportionate value from users.

    • Scenario 3: Denial of Service

      • By deploying pools with conflicting or invalid configurations, the attacker could disrupt the protocol's operations or cause degradation in service quality.

    • Scenario 4: Phishing Attacks

      • The attacker presents the malicious pool as a legitimate one, tricking users into interacting with it and suffering losses.

  4. Impact on Users and Protocol:

    • Users may lose funds when interacting with malicious pools.

    • Trust in the protocol diminishes due to the presence of exploitable pools.

    • The integrity of the Balancer ecosystem is compromised.


Proof of Concept (PoC):

  1. Attacker Deploys Pool with Malicious Token:

    // Attacker's malicious token contract
    contract MaliciousToken {
    // Token code with backdoors or non-standard behavior
    }
    // Deploy the malicious token
    MaliciousToken maliciousToken = new MaliciousToken();
    // Attacker's parameters
    NewPoolParams memory params = NewPoolParams({
    name: "Malicious Pool",
    symbol: "MAL",
    tokens: [
    TokenConfig({
    token: IERC20(maliciousToken),
    assetManager: address(0)
    })
    ],
    normalizedWeights: [1e18],
    roleAccounts: defaultRoleAccounts,
    swapFeePercentage: 0.003e18,
    poolHooksContract: address(0),
    enableDonation: false,
    disableUnbalancedLiquidity: false,
    salt: attackerChosenSalt,
    // Other required parameters...
    });
    // Attacker calls create function
    (address pool, ) = quantAMMWeightedPoolFactory.create(params);
  2. Users Interact with Malicious Pool:

    • Users see the pool listed and attempt to swap or provide liquidity.

    • The malicious token executes harmful code during these interactions, leading to fund theft.

  3. Attacker Exploits Incorrect Weights:

    • By setting normalizedWeights that favor the attacker's token, swap calculations provide the attacker with more value than intended.

    • For example, setting the attacker's token weight to near 1e18 and others to minimal values leads to skewed pricing.


Recommendation:

Implement strict input validation in the create function to prevent attackers from deploying pools with malicious or invalid parameters.

Validation Steps:

  1. Weights Sum to 1e18:

    uint256 totalWeight;
    for (uint256 i = 0; i < params.normalizedWeights.length; i++) {
    require(params.normalizedWeights[i] > 0, "Weights must be positive");
    totalWeight += params.normalizedWeights[i];
    }
    require(totalWeight == FixedPoint.ONE, "Weights must sum to 1e18");
  2. Tokens Are Valid ERC20 Contracts:

    for (uint256 i = 0; i < params.tokens.length; i++) {
    IERC20 token = params.tokens[i].token;
    require(address(token) != address(0), "Token address cannot be zero");
    require(_isContract(address(token)), "Token must be a contract");
    // Optionally, check token's totalSupply or symbol to confirm ERC20 compliance
    }

    Implement _isContract helper function:

    function _isContract(address account) internal view returns (bool) {
    return account.code.length > 0;
    }
  3. Pool Registry and Details Validation:

    • Enforce size limits on poolDetails to prevent excessive data.

    • Validate poolRegistry to ensure it matches expected configurations.

  4. Block Malicious Tokens:

    • Maintain a registry of disallowed tokens, or use a whitelist approach to only allow known safe tokens.

    • Alternatively, integrate with third-party services to check for token security.

Modified Code Example:

function create(NewPoolParams memory params) external returns (address pool, bytes memory poolArgs) {
require(params.normalizedWeights.length == params.tokens.length, "Mismatched tokens and weights");
require(params.normalizedWeights.length > 0, "At least one token required");
uint256 totalWeight;
for (uint256 i = 0; i < params.normalizedWeights.length; i++) {
require(params.normalizedWeights[i] > 0, "Weights must be positive");
totalWeight += params.normalizedWeights[i];
IERC20 token = params.tokens[i].token;
require(address(token) != address(0), "Token address cannot be zero");
require(_isContract(address(token)), "Token must be a contract");
// Optional: Additional ERC20 compliance checks
}
require(totalWeight == FixedPoint.ONE, "Weights must sum to 1e18");
// Validate poolRegistry and poolDetails as needed
// Proceed with pool creation
// ...
}
Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas / Admin is trusted / Pool creation is trusted / User mistake / Suppositions

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Appeal created

galturok Submitter
10 months ago
galturok Submitter
10 months ago
galturok Submitter
10 months ago
huntoor Auditor
10 months ago
n0kto Lead Judge
10 months ago
n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas / Admin is trusted / Pool creation is trusted / User mistake / Suppositions

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!