Overview
This report covers the security review of DIN AVS, which is an AVS implementation for EigenLayer, developed by Infura. Our security assessment was a full review of the code, spanning a total of 1 week. During our review, we did not identify any major severity vulnerabilities. We did identify several minor severity vulnerabilities and code optimisations. All of our reported issues were fixed or acknowledged by the development team and consequently validated by us. We can confidently say that the overall security and code quality have increased af ter completion of our audit
Scope
The analyzed resources are located on:
https://github.com/DIN-center/din-avs/tree/3200004d10d3a1b10b9a40bf3adecb870906b036
The issues described in this report were fixed in the following commit:
https://github.com/DIN-center/din-avs/commit/6e8deb6777368d74f9b7169cc23d875cb09a446d
Summary
Weaknesses
This section contains the list of discovered weaknesses.
INFU1-1 | PRE-VETO OPERATOR REMOVAL ON SLASHING QUEUE LACKS AUTOMATIC ROLLBACK
Severity:
Status:
Acknowledged
Path:
src/ServiceManager.sol
Description:
In ServiceManager.queueSlashingRequest(), the function immediately removes the operator from the allowlist, disqualifies them, and deregisters them from operator sets before the veto period concludes. When the veto committee cancels a slashing request via VetoableSlasher.cancelSlashingRequest(), only the slashing request status is updated to Cancelled, but the operator's state changes (allowlist removal, disqualification, deregistration) are not reverted.
This defeats part of the purpose of the veto mechanism, which is designed to prevent incorrect slashing actions. As a result, an authorized watcher can cause disruptive state changes that persist even if the veto committee cancels the request.
Example scenario:
- A Watcher queues a slashing request (whether by mistake or misjudgment)
- The operator is immediately removed from allowlist, disqualified, and deregistered
- The operator cannot provide services during the veto period
- The veto committee identifies the error and cancels the request
- The operator's funds are protected, but the operator remains in a disabled state
- Manual recovery is required: Allowlister must re-add to allowlist, Owner must re-qualify, and operator must re-register
function queueSlashingRequest(IAllocationManager.SlashingParams calldata params) external override onlyWatcher {
// Ensure the operator is not a watcher or router
require(params.operatorSetId > WATCHER_OPERATOR_SET_ID, "can't slash watchers or routers");
// Validate slashing parameters to prevent precision loss
for (uint256 i = 0; i < params.strategies.length; i++) {
// Calculate percentage from wads (params.wadsToSlash is in 18 decimal precision)
uint256 slashPercentage = params.wadsToSlash[i];
validateSlashingParams(params.operator, params.strategies[i], slashPercentage);
}
_queueSlashingRequest(params);
_removeOperatorFromAllowlist(uint8(params.operatorSetId), params.operator);
_disqualify(uint8(params.operatorSetId), params.operator);
// Deregister operator from operator sets
uint32[] memory operatorSetIds = new uint32[](1);
operatorSetIds[0] = params.operatorSetId;
IAllocationManagerTypes.DeregisterParams memory deregisterParams = IAllocationManagerTypes.DeregisterParams({
operator: params.operator,
avs: address(this),
operatorSetIds: operatorSetIds
});
allocationManager.deregisterFromOperatorSets(deregisterParams);
}
Remediation:
Defer side effects to fulfillment: move allowlist removal, disqualification, and deregistration to the slashing fulfill path so they occur only after the veto window has passed and the request is fulfilled.
Or add rollback on cancel: record the operator's pre‑queue allowlist/qualification/registration state (and any data needed to restore it) and, upon cancellation, restore those states; only apply permanent removal during fulfillment.
Commentary from the client:
Intended design choice.
INFU1-4 | REGISTRY NOT REFRESHED AFTER SLASHING FULFILLMENT, CAUSING DELAYED ENFORCEMENT
Severity:
Status:
Fixed
Path:
src/ServiceManager.sol
Description:
The ServiceManager.fulfillSlashingRequest() function overrides VetoableSlasher but omits the call to slashingRegistryCoordinator.updateOperators() that synchronizes registry state after slashing execution. The base implementation performs this update atomically to ensure StakeRegistry and IndexRegistry reflect post-slashing magnitudes and trigger automatic enforcement actions such as removing operators who fall below minimum stake thresholds.
This creates a state inconsistency where registry-coordinator–derived views lag behind the operator's actual post-slash status. As a result, follow-on enforcement actions that depend on these views, such as minimum stake validation for a quorum, are not triggered immediately.
function fulfillSlashingRequest(uint256 requestId) external override onlyWatcher {
IVetoableSlasher.VetoableSlashingRequest storage request = slashingRequests[requestId];
require(block.number >= request.requestBlock + vetoWindowBlocks, VetoPeriodNotPassed());
require(request.status == SlashingStatus.Requested, SlashingRequestIsCancelled());
request.status = SlashingStatus.Completed;
_fulfillSlashingRequest(requestId, request.params);
}
Remediation:
After fulfilling a slashing request in ServiceManager, perform an immediate registry refresh consistent with the base behavior by calling slashingRegistryCoordinator.updateOperators (or an equivalent quorum-scoped update) for the affected operator(s). Ensure all slashing paths apply a consistent post-slash refresh so enforcement dependent on registry state occurs without delay.
INFU1-2 | PINNED EIGENLAYER-MIDDLEWARE V1.3.0 MAY LACK AUDIT FIXES AND INCLUDES NOT-FULLY-AUDITED MODULES
Severity:
Status:
Fixed
Description:
The project pins eigenlayer-middleware to v1.3.0, while v1.3.1 is available with slashing audit fixes. The v1.3.1 release addresses one Medium severity issue and several Low severity issues in the upstream middleware contracts.
Since DINRegistryCoordinator inherits from SlashingRegistryCoordinator and configures a churnApprover, the project potentially inherits these issues through the dependency chain. The risk is inherited at the dependency level and requires a buggy churn approver to materialize.
Remediation:
Update the eigenlayer-middleware submodule to v1.3.1 or later, adjust Foundry remappings accordingly, and verify compatibility with any nested dependencies such as eigenlayer-contracts. Recompile and test to ensure the update does not introduce breaking changes.
INFU1-5 | MISMATCH IN SLASHING VALIDATION LOGIC CAN LEAD TO FALSE NEGATIVES
Severity:
Status:
Fixed
Path:
src/ServiceManager.sol
Description:
The pre-flight validation logic in ServiceManager.calculateExpectedSlash is inconsistent with the execution logic in AllocationManager.slashOperator. This discrepancy can cause the validation to incorrectly reject valid slashing transactions.
The two key differences are:
- Calculation Basis: The validation uses an operator's
getMaxMagnitude, whereas the core execution logic uses thecurrentMagnitudeof the allocation. - Rounding Policy: The validation's division implicitly rounds down, while the
AllocationManagerexplicitly rounds up usingmulWadRoundUp. As a result, the validation logic is overly conservative. This can lead to a "false negative" where a legitimate slash - particularly one involving a small percentage near the precision boundary - is calculated to have an expected amount of zero and is reverted, even though it would have been successfully processed by theAllocationManager.
function calculateExpectedSlash(address operator, IStrategy strategy, uint256 slashPercentage)
internal
view
returns (uint256 expectedSlash)
{
// slither-disable-next-line calls-loop
uint64 maxMagnitude = allocationManager.getMaxMagnitude(operator, strategy);
expectedSlash = (uint256(maxMagnitude) * slashPercentage) / 1e18;
}
Remediation:
Update calculateExpectedSlash() to query the operator's current allocation for the specific operator set and strategy using getAllocation(), then apply the same round-up multiplication logic that AllocationManager uses during actual slash execution.
INFU1-3 | UNUSED IMPORT AND CUSTOM ERROR IN SERVICEMANAGER
Severity:
Status:
Fixed
Description:
The ServiceManager.sol contract contains an unused import and an unused custom error definition.
- The import
ISlashingRegistryCoordinatorTypesis included but is not referenced anywhere in the contract. - The custom error
SlashingPeriodOveris defined but is never reverted.
Remediation:
Remove the unused import statement for ISlashingRegistryCoordinatorTypes and the unused custom error declaration SlashingPeriodOver from ServiceManager.sol.