docs(runbook): verify fee account trustline before registering tokens or rotating fee account (closes #141) - #146
Conversation
…nbook (closes boundlessfi#141) - Add `./scripts/admin/verify-fee-trustline.sh` to pre-flight verify fee account trustlines and authorization status across registered tokens (mitigating DoS.15). - Update `docs/multisig-preflight.md` with fee account pre-flight trustline verification checklist before `register_supported_token` and `set_fee_account`. - Update `docs/contract-ops-runbook.md` with operational trustline validation procedures and event alerting guidelines on `FeeAccountUpdated` and `TokenRegistered`. - Link trustline check into `scripts/admin/verify-multisig.sh` next-step guidance.
|
|
||
| # Match either exact code+issuer or asset code | ||
| MATCH=$(echo "$BALANCES" | jq -r --arg code "$CODE" --arg issuer "$ISSUER" \ | ||
| '[.[] | select(.asset_code == $code and (.asset_issuer == $issuer or $code == $issuer))] | .[0]') |
There was a problem hiding this comment.
Business Logic: false positive issuer match in verify-fee-trustline.sh
The trustline match predicate can succeed even when the provided issuer does not match, because it includes (.asset_issuer == $issuer or $code == $issuer). If an operator supplies malformed input (e.g., missing :ISSUER) or an attacker convinces ops to verify only by ASSET_CODE, the script may incorrectly PASS a fee account that lacks the correct trustline, leaving deposit_with_fee_at / release_with_fee_at vulnerable to the same revert/DoS condition this PR aims to mitigate.
Require exact asset_code+asset_issuer matching for credit assets (and reject inputs that are not CODE:ISSUER), so the script cannot pass on code-only matches or wrong issuers.
| '[.[] | select(.asset_code == $code and (.asset_issuer == $issuer or $code == $issuer))] | .[0]') | |
| '[.[] | select(.asset_code == $code and .asset_issuer == $issuer)] | .[0]') |
Fix with MCP
Almanax found a vulnerability. Can you take a look and fix it?
Finding ID: 8b0424b8-3a25-4529-bfae-b9d14299c424
Actions
- Reply
/almanax ask <question>to ask a follow-up question. - Reply
/almanax dismiss [<reason>]and it won't appear again in future scans. - Reply
/almanax resolve [<reason>]to mark the finding as resolved. - Reply
/almanax severity <level> [<reason>]to override the severity.
| '[.[] | select(.asset_code == $code and (.asset_issuer == $issuer or $code == $issuer))] | .[0]') | ||
|
|
||
| if [[ -n "$MATCH" && "$MATCH" != "null" ]]; then | ||
| IS_AUTH=$(echo "$MATCH" | jq -r '.is_authorized // true') |
There was a problem hiding this comment.
Input and Parameter Validation: non-conservative is_authorized default in verify-fee-trustline.sh
For required trustlines, the script treats missing .is_authorized as true (.is_authorized // true). If Horizon omits this field in some responses/edge cases, the script can incorrectly mark an unauthorized trustline as authorized, again undermining the operational DoS mitigation.
Default missing .is_authorized to false when asserting required trustlines, so the script fails closed and forces manual verification.
| IS_AUTH=$(echo "$MATCH" | jq -r '.is_authorized // true') | |
| IS_AUTH=$(echo "$MATCH" | jq -r '.is_authorized // false') |
Fix with MCP
Almanax found a vulnerability. Can you take a look and fix it?
Finding ID: deb2bf4e-96f1-4373-b765-d78b568850d8
Actions
- Reply
/almanax ask <question>to ask a follow-up question. - Reply
/almanax dismiss [<reason>]and it won't appear again in future scans. - Reply
/almanax resolve [<reason>]to mark the finding as resolved. - Reply
/almanax severity <level> [<reason>]to override the severity.
…d check - Enforce exact `.asset_code == $code and .asset_issuer == $issuer` matching in `verify-fee-trustline.sh`. - Default missing `.is_authorized` to `false` (fail-closed validation). - Addresses review feedback from @almanax-ai[bot].
|
Thank you for the review @almanax-ai[bot]! Updated
/almanax resolve |


Summary of Changes
Addresses Issue #141 and threat model finding DoS.15 (unverified fee account trustlines leading to transaction reverts during protocol fee collection in
deposit_with_fee_at/release_with_fee_at):scripts/admin/verify-fee-trustline.sh):fee_accountG-addresses exist, hold active trustlines for required/registered asset pairs, and haveis_authorized: true.docs/multisig-preflight.md):register_supported_tokenorset_fee_accountoperations.docs/contract-ops-runbook.md):FeeAccountUpdatedandTokenRegistered.scripts/admin/verify-multisig.sh:Closes #141.