Cryptography & Blockchain Security

Chapter 9
Smart Contract and Decentralized Application Security

Advance Diploma in Blockchain
Cryptography & Blockchain Security   •   Advance Diploma

Smart Contract and Decentralized Application Security

Introduction and Context

Smart contracts are programs deployed to a blockchain whose execution is replicated and whose state transitions are governed by consensus. A decentralized application (dApp) combines one or more smart contracts with user interfaces, wallets, off-chain services, oracles, indexing systems, and governance processes. Security therefore extends beyond source code. It includes economic incentives, transaction ordering, key management, external data, upgrade procedures, and operational monitoring.

A smart contract may be immutable after deployment, but its consequences are not reversible in the ordinary sense. A coding error can lock funds permanently, authorize an attacker, manipulate a market, or undermine confidence in an entire protocol. Security engineering must consequently address three related properties:

  • Confidentiality: usually limited on public blockchains because contract state and transactions are observable.
  • Integrity: unauthorized or invalid state changes must be prevented.
  • Availability: legitimate users must be able to interact with the system within block and gas constraints.

For blockchain applications, integrity and availability are especially prominent. A secure design also requires correctness under adversarial transaction ordering and hostile contract composition.

Learning Objectives

By the end of this chapter, a learner should be able to:

  1. Explain the execution model of smart contracts and dApps.
  2. Identify reentrancy, access-control, arithmetic, oracle, front-running, denial-of-service, and upgradeability vulnerabilities.
  3. Apply checks-effects-interactions, pull payments, least privilege, pausability, and safe upgrade patterns.
  4. Construct threat models and security invariants.
  5. Use testing, fuzzing, static analysis, symbolic execution, and formal verification appropriately.
  6. Evaluate audit findings, governance risks, and responsible disclosure practices.

1. The Smart-Contract Threat Model

A contract executes deterministically given blockchain state, transaction input, and protocol rules. Determinism does not imply safety: an attacker can choose inputs, deploy malicious contracts, submit transactions strategically, and exploit assumptions made by developers.

Important attack surfaces include:

  • externally callable functions and fallback or receive functions;
  • token standards and non-standard token implementations;
  • calls to arbitrary addresses;
  • delegate calls and proxy storage layouts;
  • price feeds and cross-chain messages;
  • privileged keys, multisignatures, and governance;
  • initialization and migration code;
  • gas limits, block limits, and transaction ordering;
  • front-end, RPC, signing, and monitoring infrastructure.

A useful threat model identifies assets, actors, trust assumptions, entry points, abuse cases, and security properties. Assets may include native currency, tokens, voting power, collateral, user identity, and protocol solvency. Actors may include ordinary users, compromised administrators, miners or validators, searchers, oracle operators, and malicious contracts.

A security invariant is a condition that must remain true after every permitted state transition. For a collateralized lending system, examples include “total borrower debt cannot exceed the value supported by collateral” and “only an authorized account can change the interest-rate model.” Invariant-based reasoning is more reliable than testing only expected user journeys.

2. Reentrancy

Reentrancy occurs when a contract transfers control to another contract before completing its own state update, allowing the called contract to call back into the original function. The callback observes an intermediate state and may repeat an action such as withdrawing funds.

A simplified vulnerable pattern is:

function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount, "insufficient");
    (bool ok, ) = msg.sender.call{value: amount}("");
    require(ok, "transfer failed");
    balances[msg.sender] -= amount;
}

The balance is reduced after the external call. A malicious recipient can re-enter withdraw while its recorded balance still appears unchanged. The safer checks-effects-interactions pattern is:

function withdraw(uint256 amount) external nonReentrant {
    require(balances[msg.sender] >= amount, "insufficient");
    balances[msg.sender] -= amount;
    (bool ok, ) = msg.sender.call{value: amount}("");
    require(ok, "transfer failed");
}

The pattern has three stages: validate conditions, update internal state, and interact externally. A reentrancy guard can provide an additional lock, but it is not a substitute for correct state design. Reentrancy can also be cross-function: a callback enters a different function that relies on the same partially updated state. Read-only reentrancy is another risk when a view-like observation is made during an intermediate state and used by another protocol.

Common defenses are:

  • update balances and status before external calls;
  • use a carefully designed reentrancy guard;
  • minimize external calls and avoid arbitrary callbacks;
  • separate accounting from settlement;
  • use pull payments, allowing recipients to withdraw rather than forcing the contract to call many recipients;
  • test malicious receiver contracts and cross-function interactions.

3. Access-Control Vulnerabilities

Access control determines who may call a function and under what conditions. A missing modifier, incorrect role assignment, unprotected initializer, or publicly writable configuration variable can turn an ordinary user into an administrator.

The principle of least privilege states that each account or role should receive only the authority required for its task. Role separation may distinguish a pauser, upgrader, treasury operator, oracle reporter, and governance executor. Administrative functions should normally use multisignature control, timelocks, or both.

Typical failures include:

  • using tx.origin for authorization instead of msg.sender;
  • assuming a constructor protects proxy deployments;
  • leaving an initializer callable more than once;
  • allowing an admin to replace critical logic without delay or notice;
  • failing to validate zero addresses and role members;
  • confusing ownership of a token with authority in a protocol.

A robust access-control design documents every privileged function, its role, the role-management procedure, and the emergency response. Privilege escalation tests should attempt every sensitive operation from unauthorized accounts.

4. Arithmetic and Data-Validation Errors

Arithmetic errors include overflow, underflow, truncation, division by zero, incorrect decimal scaling, and unsafe type conversions. In Solidity versions with checked arithmetic, overflow and underflow generally revert by default; unchecked blocks deliberately remove this protection and require a proven bound.

For non-negative integer values, a multiplication followed by division should be designed carefully. The expression

q = (a × b) ÷ d

uses integers a, b, and positive divisor d; Solidity integer division truncates toward zero. The result is safe only if the intended economic rule permits truncation and the intermediate product does not overflow. Reordering operations can change rounding and may introduce exploitable bias. Decimal tokens also differ in precision, so unit conventions must be explicit.

A protocol should define whether rounding favors the user, protocol, creditor, or debtor. It should test boundary values, zero values, maximum integers, negative-value assumptions where signed types are used, and conversions between token decimals. Time calculations require similar care: block timestamps are not precise clocks and should not be treated as unpredictable randomness.

5. Oracle and External-Data Risks

Smart contracts cannot directly query arbitrary off-chain information. Oracles bridge external data into consensus, creating risks of manipulation, delay, incorrect decimals, stale reports, and operator compromise.

A price oracle should be evaluated for:

  • source diversity and independence;
  • update frequency and maximum permitted age;
  • deviation limits and circuit breakers;
  • liquidity and resistance to temporary price manipulation;
  • fallback behavior when data is unavailable;
  • decimal and unit consistency;
  • governance and reporter incentives.

A single spot price from a thin market can be manipulated within one transaction or block. Time-weighted averages reduce sensitivity to short-lived movements but introduce delay. No oracle is universally safe: the appropriate design depends on market liquidity, attack cost, update latency, and the value at risk.

Contracts should reject stale or invalid data, define acceptable bounds, and pause sensitive operations if an oracle fails. However, emergency mechanisms themselves require access control and transparent governance.

6. Front-Running and Transaction-Ordering Attacks

Transactions are often visible before confirmation. Searchers may observe a pending transaction and submit another transaction with a higher fee or otherwise favorable ordering. This is commonly called front-running, although the broader issue is transaction-order dependence or maximal extractable value (MEV).

Examples include buying an asset before a visible user purchase, copying a profitable arbitrage, or changing a parameter before a governance action. A decentralized exchange trade can suffer sandwiching: an attacker trades before and after a victim to exploit the victim’s price impact.

Defenses include:

  • slippage limits and deadlines;
  • commit-reveal schemes, in which a commitment is submitted before the hidden action is revealed;
  • batch auctions and frequent clearing;
  • private transaction submission where appropriate;
  • minimum and maximum bounds on user orders;
  • designs that do not expose valuable information before execution.

Commit-reveal systems must handle non-revelation, replay, and commitment collisions. A commitment normally includes a secret nonce and enough context to prevent reuse. Privacy is not absolute: metadata, timing, and later revelation may still disclose information.

7. Denial of Service and Gas-Related Failure

A denial-of-service vulnerability prevents valid operations from completing. In smart contracts, this may result from unbounded loops, a malicious recipient reverting, storage growth, block gas limits, or an attacker deliberately occupying a scarce resource.

A vulnerable payout loop might attempt to send funds to every participant in one transaction. As the participant list grows, execution may exceed the block gas limit. If one recipient reverts, all payments may fail. Pull-payment architecture avoids this by recording each entitlement and allowing recipients to withdraw independently.

Other controls include bounded batches, pagination, withdrawal credits, emergency escape paths, and limits on array growth. Developers must not assume that a transaction will remain affordable as state grows. Gas griefing may also occur when an attacker causes a caller to perform expensive work without proportional compensation.

8. Upgradeability and Governance Risk

Upgradeability allows a proxy to delegate calls to implementation logic that can be replaced. It supports bug fixes but introduces administrative and storage risks.

Key concerns include:

  • unauthorized implementation replacement;
  • uninitialized or reinitialized proxies;
  • storage-slot collisions;
  • changed variable ordering or incompatible types;
  • broken storage gaps;
  • implementation self-destruction or unsafe delegate calls;
  • governance capture and rushed upgrades;
  • differences between audited code and deployed code.

Transparent proxies and universal upgradeable proxies use different dispatch and administrative models; either can be secure if correctly implemented and governed. An upgrade process should include storage-layout validation, deployment simulation, multisignature approval, a timelock, public change documentation, and a tested rollback or emergency pause strategy. Immutability is not always safer: an immutable but flawed contract may be impossible to repair. Upgradeability is therefore a governance trade-off, not simply a technical feature.

9. Secure Design Patterns

Checks-effects-interactions

Validate preconditions first, update internal state second, and perform external calls last. This reduces reentrancy exposure and makes state transitions easier to reason about.

Pull over push

Record obligations and let beneficiaries claim them. This limits dependence on recipient behavior and avoids unbounded loops.

Fail safely

Reject invalid states rather than continuing with corrupted data. Pausable controls can limit damage, but pause authority, scope, and unpause procedures must be explicit.

Capability and role separation

Use narrowly scoped roles and avoid a single externally owned account controlling every critical action. Multisignature wallets reduce single-key risk but do not remove signer collusion or phishing risk.

Explicit invariants and accounting

Track total liabilities, reserves, shares, and units with clearly specified rounding. Use internal accounting rather than trusting arbitrary token return behavior. Safe token wrappers and compatibility checks are essential because token implementations may not perfectly conform to standards.

Defense in depth

No single library or audit guarantees security. Combine language-level checks, access control, monitoring, economic limits, incident procedures, and independent review.

10. Testing and Formal Verification

Testing should proceed from inexpensive checks to stronger assurance:

  1. Unit tests: verify individual functions and boundary conditions.
  2. Integration tests: exercise token, oracle, governance, and proxy interactions.
  3. Invariant and property-based tests: generate many states and assert that properties remain true.
  4. Fuzzing: supply unexpected sequences, values, callers, and timing conditions.
  5. Static analysis: identify reentrancy patterns, dangerous calls, and access-control errors.
  6. Symbolic execution: explore paths using symbolic inputs, subject to tool limits.
  7. Formal verification: mathematically prove specified properties under a defined model.

Formal verification does not prove that a protocol specification is economically sound or that the deployed bytecode matches the verified artifact unless the whole chain is controlled. It also cannot automatically establish the absence of every implementation, oracle, governance, or operational risk. The central task is to state properties precisely. For example, “withdrawal never exceeds the caller’s available balance” is testable; “the contract is secure” is not a useful formal property.

A security testing matrix should include unauthorized callers, malicious receivers, stale oracle values, extreme prices, failed external calls, repeated initialization, upgrade attempts, transaction ordering, and state growth.

11. Professional Audit Practice

An audit is a time-bounded assessment, not a warranty. Before review, the project should freeze the commit, document architecture and trust assumptions, provide deployment addresses, identify known limitations, and specify invariants. Auditors should review code, configuration, dependencies, deployment scripts, privileged roles, and economic mechanisms.

Findings should state the affected component, vulnerability, exploit scenario, impact, likelihood, evidence, and remediation. Severity should reflect realistic loss and exploitability rather than stylistic preference. Developers should reproduce findings, apply fixes, add regression tests, and request verification of remediation. Independent review is especially valuable for high-impact changes.

Operational security continues after deployment. Monitoring should detect abnormal withdrawals, oracle deviations, role changes, implementation upgrades, paused states, and unusual gas or transaction patterns. Incident response should define authority, communication channels, containment actions, evidence preservation, and disclosure principles.

12. Illustrative Case Study: A Vulnerable Lending Market

Background. Consider a fictional lending dApp, HarborLend, that accepts a collateral token and allows users to borrow a stable token. Its contract obtains collateral prices from an on-chain spot pool and permits an administrator to upgrade the implementation.

Problem. An attacker discovers three weaknesses: the price source has low liquidity, the liquidation function trusts a stale value, and the upgrade administrator is a single externally owned account. The withdrawal function also transfers reward tokens before reducing the user’s reward balance.

Analysis. The spot pool can be moved temporarily at relatively low cost. If the manipulated price makes collateral appear valuable, the attacker can borrow more stable tokens than the collateral supports. A stale-price path can prolong the discrepancy. The reward transfer creates a reentrancy opportunity if the reward token invokes recipient code. Finally, compromise of the administrator permits replacement of the implementation and theft of reserves.

Approach. The team first pauses new borrowing and preserves logs. It replaces the spot price with a multi-source, freshness-checked oracle and adds deviation limits. Borrowing and liquidation use explicit decimal conversions and conservative rounding. Reward accounting follows checks-effects-interactions and uses a reentrancy guard. The upgrade role moves to a multisignature wallet with a timelock; deployment scripts verify implementation and storage layout. Fuzz tests assert that total debt remains within permitted collateral value under bounded oracle conditions.

Outcome. The immediate exploit paths are closed, but the protocol’s risk is not eliminated. Oracle failure, governance capture, and token-specific behavior remain monitored risks. The team publishes a post-incident report, compensates affected users according to a governed plan, and commissions an independent review.

Learning points. Vulnerabilities frequently interact. A price-manipulation defect becomes more damaging when accounting assumptions are weak; a technically correct patch is insufficient if privileged upgrade keys remain exposed. Security is a lifecycle involving design, implementation, deployment, governance, monitoring, and response.

13. Ethical, Legal, and Governance Considerations

Security researchers should follow responsible disclosure: preserve evidence, contact the project privately, allow reasonable remediation time, and avoid unnecessary exposure of users. Exploiting a discovered vulnerability may cause legal and ethical harm even when funds can technically be recovered. Bug-bounty terms should define scope, safe-harbor provisions, reward criteria, and communication procedures.

Protocols must also consider consumer protection, sanctions and identity requirements where applicable, data protection, financial regulation, and jurisdictional uncertainty. Public blockchains make transactions durable and observable; personal data should not be placed on-chain without a clear legal and technical basis. Governance should disclose conflicts of interest and distinguish emergency authority from ordinary policy-making.

14. Contemporary Developments and Limitations

Current practice increasingly combines account abstraction, rollups, cross-chain messaging, zero-knowledge systems, automated monitoring, and AI-assisted code analysis. These technologies introduce new assumptions. Cross-chain bridges expand the trusted computing base; rollups depend on sequencer and proof systems; account abstraction changes validation and replay considerations; AI tools can identify patterns but may miss economic exploits and can produce false confidence.

Security tools also have limits. Static analyzers may generate false positives and miss logic flaws. Fuzzers explore only sampled paths. Audits depend on scope and time. Formal proofs depend on specifications and models. Economic attacks require analysis of incentives, liquidity, and adversarial behavior, not only source-code correctness.

The most defensible engineering posture is layered assurance: minimize authority, specify invariants, constrain economic loss, validate external data, test adversarially, verify deployment artifacts, monitor continuously, and maintain a credible response plan.

Chapter Summary

Smart-contract security is the protection of blockchain-controlled assets and state against programming, economic, governance, and operational threats. Reentrancy is reduced by state updates before external calls, guards, and pull payments. Access control requires least privilege, role separation, protected initialization, and governed administration. Arithmetic safety requires checked operations, explicit units, bounded conversions, and deliberate rounding. Oracle designs must address manipulation, freshness, source diversity, and failure. Front-running is mitigated through slippage controls, commitments, batching, and privacy-aware transaction mechanisms. Denial of service requires bounded work and pull-based settlement. Upgradeability offers repairability but creates proxy, storage, key, and governance risks.

A mature security process combines threat modeling, invariants, unit and property-based testing, fuzzing, static and symbolic analysis, formal verification where appropriate, independent audits, deployment controls, monitoring, and responsible incident response. No single technique proves that a dApp is safe; security is a continuing system and governance discipline.

Key Terms

Smart contract: A blockchain program that executes state transitions according to encoded rules.

Decentralized application: An application combining blockchain contracts with user and supporting services.

Reentrancy: Repeated entry into a contract before a previous execution has completed its state update.

Checks-effects-interactions: A pattern that validates, updates state, and then performs external calls.

Access control: Rules determining which accounts or roles may perform operations.

Least privilege: Granting only the authority necessary for a task.

Oracle: A mechanism that supplies external data to a blockchain contract.

Stale data: Information older than the permitted freshness interval.

Front-running: Acting on observable pending information to obtain a transaction-order advantage.

MEV: Value extracted by controlling or influencing transaction ordering.

Denial of service: Preventing legitimate operations from completing.

Pull payment: A design in which beneficiaries claim recorded funds themselves.

Proxy: A contract that delegates execution to replaceable implementation logic.

Delegate call: Execution of another contract’s code using the caller’s storage and context.

Invariant: A property that must remain true across valid state transitions.

Fuzzing: Automated testing with many generated inputs and execution sequences.

Formal verification: Mathematical analysis demonstrating specified properties under a model.

Timelock: A mandatory delay between approving and executing a sensitive action.

Multisignature wallet: A wallet requiring several authorized signatures for an operation.

Threat model: A structured description of assets, actors, assumptions, and attack surfaces.

Review Questions

5 Short Answer Questions

  1. What is reentrancy, and why does updating state after an external call create risk?
  2. State two reasons why a spot-price oracle may be unsafe.
  3. What problem does a pull-payment design address?
  4. Why must proxy contracts have protected initialization procedures?
  5. Distinguish fuzz testing from formal verification.

5 Long Answer Questions

  1. Explain the checks-effects-interactions pattern and discuss situations in which a reentrancy guard alone may be insufficient.
  2. Compare the security benefits and risks of immutable contracts and upgradeable proxy systems.
  3. Design an access-control model for a protocol with pausing, upgrades, oracle administration, and treasury withdrawals.
  4. Explain how front-running and transaction ordering affect decentralized exchanges and evaluate three mitigation techniques.
  5. Develop a complete security-testing plan for a lending dApp, including invariants, tools, and deployment checks.

3 Analytical / Application Questions

  1. A contract pays 10,000 users in one loop and one recipient can deliberately revert. Analyze the availability risks and propose a replacement architecture.
  2. A lending protocol uses a low-liquidity price pool and permits borrowing immediately after a large price change. Construct an attack path and specify oracle and accounting controls.
  3. An upgrade proposal is approved by one administrator and executed immediately. Evaluate the governance risk and design a safer approval, delay, monitoring, and emergency process.

Multiple Choice Questions with Answers

Question 1

Which sequence best represents the checks-effects-interactions pattern?

A. External call, validation, state update

B. Validation, state update, external call

C. State update, external call, validation

D. Validation, external call, state update

Correct Answer: B. Validation, state update, external call

Question 2

What is the primary danger in the vulnerable withdrawal pattern that reduces a balance only after sending funds?

A. Integer precision loss

B. Oracle staleness

C. Reentrancy

D. Storage-slot collision

Correct Answer: C. Reentrancy

Question 3

Which control most directly limits the authority of a protocol administrator?

A. Least-privilege role separation

B. Increasing block size

C. Using a larger token supply

D. Disabling event logs

Correct Answer: A. Least-privilege role separation

Question 4

Why can a low-liquidity spot price be dangerous for a lending protocol?

A. It prevents all transactions from being signed

B. It can be moved temporarily at relatively low cost

C. It automatically encrypts collateral values

D. It guarantees stale data is rejected

Correct Answer: B. It can be moved temporarily at relatively low cost

Question 5

Which design best reduces denial of service caused by one recipient reverting during mass payout?

A. A single unbounded payout loop

B. A push payment to every recipient

C. A pull-payment claim mechanism

D. Removing all balance checks

Correct Answer: C. A pull-payment claim mechanism

Question 6

What is a major risk specific to upgradeable proxy systems?

A. They cannot contain state

B. They eliminate governance requirements

C. They may suffer from unauthorized upgrades or storage-layout errors

D. They make all oracle data private

Correct Answer: C. They may suffer from unauthorized upgrades or storage-layout errors

Question 7

Which technique generates many unexpected inputs and execution sequences automatically?

A. Fuzzing

B. Multisignature approval

C. Timelocking

D. Token minting

Correct Answer: A. Fuzzing

Question 8

What is the purpose of a transaction deadline and slippage limit on a decentralized exchange order?

A. To increase oracle centralization

B. To constrain execution under unfavorable price or timing conditions

C. To permit unlimited price movement

D. To disable transaction ordering

Correct Answer: B. To constrain execution under unfavorable price or timing conditions

Question 9

Which statement about formal verification is most accurate?

A. It proves every economic and operational risk is absent

B. It is useful only for user-interface testing

C. It demonstrates specified properties under a defined model

D. It removes the need to verify deployed bytecode

Correct Answer: C. It demonstrates specified properties under a defined model

Question 10

Which governance arrangement generally improves control of a critical upgrade?

A. An unprotected public initializer

B. One externally owned account with immediate execution

C. A multisignature approval followed by a timelock

D. A random user selected at each block

Correct Answer: C. A multisignature approval followed by a timelock

Cryptography & Blockchain Security
Chapter 9 of 14