diff --git a/contracts/origin-credential-mint/lib.rs b/contracts/origin-credential-mint/lib.rs index ede489d..5e42ad9 100644 --- a/contracts/origin-credential-mint/lib.rs +++ b/contracts/origin-credential-mint/lib.rs @@ -147,8 +147,21 @@ mod origin_credential_mint { AlreadyExpired, InvalidConfiguration, TransferFailed, + /// Audit 2026-07-04: el holder alcanzó el máximo de credenciales + /// (`MAX_CREDENTIALS_PER_HOLDER`) — cota anti-griefing/DoS. Sin esto, un + /// issuer malicioso bloateaba el `Vec` del holder hasta que cualquier + /// operación que lo cargue (issue/read) excedía el gas. + HolderCredentialLimitReached, } + /// Máximo de credenciales por holder (cota anti-griefing del `Vec` en storage). + /// Una persona/entidad tiene un número acotado de credenciales legítimas; el + /// límite evita que un issuer malicioso infle el `Vec` de una víctima hasta + /// hacerlo ilegible por gas. (El índice `issuer_credentials` de un emisor de + /// alto volumen debe migrar a un índice paginado `Mapping<(issuer,i),id>` — + /// trabajo futuro; no es un vector de griefing de terceros.) + pub const MAX_CREDENTIALS_PER_HOLDER: u32 = 512; + pub type Result = core::result::Result; /// Convierte un valor `U256` del entorno pallet-revive a `Balance` (u128) @@ -289,6 +302,11 @@ mod origin_credential_mint { // Update indices canonical let mut holder_list = self.holder_credentials.get(holder).unwrap_or_default(); + // Audit 2026-07-04: cota anti-griefing — sin esto un issuer malicioso + // bloatea el Vec del holder hasta hacerlo ilegible por gas. + if holder_list.len() as u32 >= MAX_CREDENTIALS_PER_HOLDER { + return Err(Error::HolderCredentialLimitReached); + } holder_list.push(id); self.holder_credentials.insert(holder, &holder_list);