All articles
Security FundamentalsJune 16, 20268 min read

Trust Assumptions in Smart Contract Audits: Fully vs Semi-Trusted Actors

Audit severity isn't a fixed property. It depends on whether the actor abusing the issue is fully trusted (governance multisig) or semi-trusted (admin, operator, oracle).

By Carlos (Bloqarl)

TL;DR

  • Audit severity is not a fixed property of a finding. It depends on who can exploit the finding and what trust assumptions the protocol explicitly grants that actor.
  • Two actor categories matter:
    • FULLY_TRUSTED: governance multisig, DAO, timelock controllers. Trusted to act in the protocol's interest by design.
    • SEMI_TRUSTED: admins, operators, keepers, oracles, MEV searchers. Have specific powers but are presumed possibly malicious or compromised.
  • Findings exploitable only by FULLY_TRUSTED actors get a -1 tier severity downgrade, with a floor of Informational. The reason: the actor would have to violate stated trust to exploit.
  • Findings exploitable by SEMI_TRUSTED actors keep their original severity. The matrix already accounts for the actor being adversarial.
  • The most common audit error is applying the wrong category. Calling a multisig "fully trusted" when it's a 2-of-3 with no timelock is wrong; that's a semi-trusted threshold and should be priced accordingly.

Why this matters

When you read an audit report, the severity column tells you what the auditors think. But severity is computed against an implicit threat model. If the threat model is wrong (e.g., assumes admin is fully trusted when it shouldn't be), the severities are wrong.

This matters in two directions:

  • For audit consumers (founders, integrators, depositors): you might trust a "Low" finding that's actually exploitable by an admin you shouldn't have trusted. Or you might dismiss a "High" that's only exploitable by your own multisig acting maliciously.
  • For auditors: applying severity correctly requires explicit modeling of trust assumptions. Auditors who skip this step produce reports that overweight or underweight findings.

The framework here is what serious audit firms use. The Plamen audit pipeline (Zealynx's automated audit framework) encodes these rules explicitly. Most rigorous audit reports include a "trust assumptions" section that lists exactly which actors are which category.

If you're a founder, this article is what to look for in audit reports. If you're an auditor, it's a checklist for the trust modeling step.

The two actor categories

FULLY_TRUSTED

Actors the protocol's design relies on to act in good faith. The protocol gives them powers because the protocol literally cannot function without trusting them at the design level.

Canonical examples:

  • Governance multisig (high threshold): a 5-of-9 multisig of doxxed reputable signers, where collusion of 5 against the protocol is implausible.
  • DAO: a token-holder vote that has demonstrated functional governance.
  • Timelock controller: a contract that delays execution of governance decisions by a meaningful period (typically 7+ days), giving the community time to respond.

The "fully trusted" classification is earned, not declared. A multisig is fully trusted if:

  • The threshold is high enough that collusion is implausible.
  • The signers are doxxed and reputable (their identity provides legal/social accountability).
  • There's no concentration (one entity doesn't control multiple keys).
  • There's a timelock or community veto on critical actions.

If any of these is missing, the multisig is semi-trusted, not fully trusted.

SEMI_TRUSTED

Actors with specific powers but no design-level guarantee of good faith. The protocol gives them powers because the alternative (full decentralization for that operation) is impractical, but the design assumes the actor might act maliciously.

Canonical examples:

  • Admin (single EOA or 1-of-N multisig): one key away from compromise. Can be socially engineered, hot-walleted, hacked.
  • Operator/keeper: third-party services that perform on-chain actions (liquidations, oracle updates). They have rate limits and bounded powers.
  • Oracle: a price-providing entity (Chainlink aggregator, custom oracle). Provides data assumed to be accurate but not infallible.
  • MEV searcher: a third-party bot that may extract value from your protocol's transactions. Assumed to be adversarial within the constraints of the protocol design.

Semi-trusted actors get full-severity findings because the protocol's design ALREADY models them as potentially adversarial. If your design relies on them not being adversarial, that's a design flaw, not a trust-classification choice.

How severity adjustments work

The standard pattern (used by Trail of Bits, OpenZeppelin, Spearbit, and most rigorous audit firms):

For FULLY_TRUSTED-only exploits

If the only path to exploit a finding is for a fully-trusted actor to violate stated assumptions:

  1. Compute the finding's severity from the standard impact × likelihood matrix.
  2. Apply a -1 tier downgrade (Critical → High, High → Medium, etc.).
  3. Floor at Informational (Low → Informational, Informational stays Informational).
  4. Note explicitly in the finding: "Severity adjusted, attack requires {actor} to violate stated trust assumption: {assumption text}."

The audit report should be transparent about the adjustment. Hiding it prevents the consumer from disagreeing with the trust model.

For SEMI_TRUSTED-exploitable findings

If a semi-trusted actor can exploit the finding within the powers the protocol grants them:

  1. Compute severity normally.
  2. No downgrade.
  3. The finding is still high-severity if the impact is high.

The reasoning: the protocol's design ALREADY assumed this actor might be malicious. If the protocol doesn't defend against malicious admin behavior, that's the bug. Don't downgrade for "well, the admin would have to act in bad faith"; bad faith is the whole point of the threat model.

For permissionless exploits

If anyone can trigger the issue without privileged access:

  1. Compute severity normally.
  2. No adjustment of any kind.

The matrix's likelihood column already accounts for accessibility ("anyone" = high likelihood, "specific conditions" = medium, "unlikely" = low).

Walkthrough: admin function

A protocol has an admin function:

function setOracle(address newOracle) external onlyAdmin {
    oracle = newOracle;
}

Finding: "Admin can set the oracle to an address they control, manipulating prices to drain the protocol."

Threat modeling:

  • Who is "admin"? If it's a single EOA: SEMI_TRUSTED. Severity stays at the matrix value (likely Critical or High, depending on TVL).
  • If it's a 5-of-9 multisig with timelock: FULLY_TRUSTED. Severity gets -1 tier downgrade and noted explicitly.

If the auditor doesn't ask "who is admin?" before classifying, they'll under- or over-rate the finding. The right report says: "If admin is a single EOA, this is Critical. If admin is a 5-of-9 multisig with 7-day timelock, this is Medium (downgraded from High due to FULLY_TRUSTED status)."

Walkthrough: governance function

A protocol has:

function executeProposal(bytes calldata data) external onlyGovernance {
    // executes arbitrary calldata
}

Finding: "Governance can execute arbitrary calls, potentially draining the protocol if a malicious proposal passes."

Threat modeling:

  • If governance is a high-threshold DAO with active turnout, snapshot voting, and 7-day timelock: FULLY_TRUSTED. Severity downgraded with explicit note.
  • If governance is a single token-holder with 51% supply: SEMI_TRUSTED at best. Severity stays.
  • If governance has any flash-loan vulnerability (vote weight checked at execution time, not snapshot): SEMI_TRUSTED, full severity.

We covered the Beanstalk case in the flash-loan article. Beanstalk's governance was SEMI_TRUSTED in practice (vulnerable to flash loans) despite the team treating it as fully trusted in their design.

Common errors

Error 1: declaring fully trusted by default

Some audit reports default to "FULLY_TRUSTED" for any actor named "admin" or "governance". This is wrong. The classification depends on the structural properties of the actor (threshold, timelock, doxxing), not the variable name.

A 1-of-1 admin EOA is SEMI_TRUSTED no matter what the variable is called.

Error 2: ignoring the trust gradient

Real protocols have multiple actors with different trust levels. The audit should classify each:

  • DEPLOYER (often abandoned key, but if not revoked, still has powers).
  • ADMIN (operational role, possibly different from deployer).
  • GOVERNANCE (long-term parameter setter).
  • OPERATOR/KEEPER (third-party automation).
  • ORACLE (price feed).

Each gets its own classification. The audit's findings list should reference the specific actor for each finding's exploitability.

Error 3: assuming timelock is sufficient

A timelock is NECESSARY for fully-trusted classification but not SUFFICIENT. A 7-day timelock with a single EOA admin is still SEMI_TRUSTED because the EOA could be compromised regardless of timelock duration.

Timelock + multisig is the minimum bar for fully-trusted. Timelock alone isn't.

Error 4: not asking the protocol team

The protocol team has explicit trust assumptions written somewhere (often in their docs or whitepaper). The auditor should ASK and CITE these. Adjusting severity based on assumed trust without confirming with the team produces reports the team disputes.

The Plamen audit framework and most rigorous human auditors include a kickoff meeting where trust assumptions are explicitly enumerated and agreed.

Related questions

Can semi-trusted actors become fully trusted over time? Yes. As a multisig matures (more signers, doxxing, timelock added), it can move from semi to fully trusted. The audit should reflect the current state, not the future state.

Are oracles always semi-trusted? Most are. Chainlink aggregator + multiple data feeds approaches "fully trusted" levels via redundancy, but a single oracle source is SEMI_TRUSTED. Custom oracles are almost always semi-trusted.

What about Layer 2 sequencers? SEMI_TRUSTED. Even with decentralization initiatives, the sequencer has powers (transaction ordering, censorship) that make it functionally semi-trusted at the design level.

How does this affect a protocol's "Critical findings" count? A protocol with many findings exploitable only by their fully-trusted multisig will see those findings downgraded. The "Critical: 0" count looks better. But the report should still detail the exposure so consumers can disagree with the trust model.

Does the trust classification affect bug bounty payouts? Often yes. Bug bounty programs (Immunefi, etc.) typically follow audit-style severity for payout sizing. Findings classified by trust model receive corresponding payouts.

What if I disagree with an auditor's trust classification? Push back. The classification is a design decision, not a fact. If your protocol's actual trust assumptions differ from the auditor's working model, fix the working model and re-classify. Audits aren't oracles; they're collaborations.

Where to see this in Academy

The Plamen audit pipeline (one of the AI auditor systems Zealynx maintains) implements this trust modeling explicitly. Findings carry trust-tagging metadata; severity adjustments are mechanical based on the tags. This is documented in Plamen's reference docs and used by the AI Auditor Builder pillar at Academy.

The eMBA Module 3 (Security from Day One) Lesson 5 (Choosing Auditors) covers what to expect from a rigorous audit, including the trust-assumptions section. If your audit doesn't include explicit trust modeling, the audit is missing a step.

The Shadow Arena targets in Academy's audit-practice layer include findings where trust modeling matters: findings that depend on admin behavior, governance behavior, or oracle behavior. Walking through these manually with the trust framework gives you calibration for real audit work.

Tagged

Audit MethodologySmart Contract SecurityTrust Models