Security, approvals and permissions
About 1553 wordsAbout 5 min
Week 0 Part 4 taught you to be careful with wallet requests. You did not yet know what a contract was.
Now you do. This page closes the loop: what is actually happening when you approve something, and what new trust you take on the moment you interact with a contract.
The shift this week made
Before Week 3, using a blockchain meant trusting the network and your own keys.
From the moment you touch a contract, you are also trusting code you did not write, cannot change, and probably have not read. That is a new row in your trust map, and it is the biggest one most people ever add.
Learning objectives
- Explain what an ERC-20 approval actually does, in contract terms
- Distinguish an on-chain approval from a signature-based permission
- Name the new trust assumptions contract interaction introduces
- Apply a short pre-approval checklist to any wallet request
Core
What an approval really is
You now know enough Solidity to see it.
A token contract holds an allowance table:
mapping(address => mapping(address => uint256)) allowances;
// owner spender amountWhen you "approve Uniswap to spend your USDC", you send a transaction calling:
approve(uniswapAddress, amount)That writes one number into that table. Nothing moves. Later, Uniswap calls transferFrom(you, someoneElse, amount), the token contract checks the allowance, and moves your tokens.
Why the two-step pattern exists at all
A contract cannot reach into your wallet. It has no key. So the only way it can ever move your tokens is if you first write permission into the token's own storage.
The design makes the spender and amount explicit. The risk depends on which contract receives permission, how much it can spend, and whether that contract remains trustworthy.
Unlimited approvals
Some interfaces request a very large or effectively unlimited allowance, so you only pay gas for the approval once. Interfaces increasingly offer spending caps instead.
approve(0x9c8a…, 115792089237316195423570985008687907853269984665640564039457584007913129639935)That number is the largest a uint256 can hold. In practice: it could cover future holdings of this token for as long as the allowance stands.
An old approval is a live liability
The allowance does not expire. It survives you forgetting about the site, the team abandoning it, and the contract being compromised eighteen months later.
If that contract is ever exploited, your tokens can be taken without you doing anything at all. You granted the permission years ago.
The defence is unglamorous and works:
| Habit | Why |
|---|---|
| Set a spending cap where the wallet allows it | Bounds the loss to what you meant to spend |
| Review approvals periodically | revoke.cash or Etherscan's Token Approvals tool |
| Use a separate wallet for experiments | An approval on a wallet with nothing in it costs nothing |
Approvals versus signatures
Two ways to hand over the same permission; one may not require gas at the moment you sign.
| Permission form | On-chain approval | Signature-based permission |
|---|---|---|
| What it is | An approve() transaction | A signed message |
| Costs gas | Yes | Often nothing |
| Visible on-chain immediately | Yes | No |
| Who submits it | You | Someone else, later |
| Grants real permission | Yes | Yes |
"No gas" is not "no risk"
A signature-based permission can create the same standing access as an approval without appearing anywhere on-chain when you sign it. It may be submitted later by someone else. A signature is not automatically dangerous: inspect what permission it authorises, who can submit it, and how long it lasts.
This is why Week 2 Part 4 says: when your wallet opens, read what it is asking. Cost is not the signal. What you are authorising is the signal.
You do not need the mechanics of permit-style signatures for Foundation. You need the takeaway: a wallet request can be dangerous even when nothing moves and nothing is charged.
The new trust assumptions
Interacting with a contract adds these, on top of everything from Week 2:
| You are trusting | Failure looks like |
|---|---|
| The contract's code is correct | Funds drained by a bug |
| The address is the real one | You interacted with a convincing fake |
| The frontend was not hijacked | The site served you a malicious transaction |
| The permissions you granted are bounded | An old allowance used against you |
| Any contract it calls is also sound | A dependency's failure becomes yours |
That last row is what composability costs. Protocols build on protocols, so a flaw three layers down can reach you.
An audit is evidence, not a guarantee
Audited protocols get exploited. An audit means competent people reviewed a specific version at a specific time, and found what they found.
It is meaningfully better than no audit. It is not a warranty.
Landscape
- Reentrancy — a called contract calls back before the first finishes. If state is updated too late, an attacker may repeat an action such as a withdrawal; the 2016 DAO hack is a famous example
- Access control bugs — a missing
requireor permission check, exactly like theVaultin Part 2. An unauthorised caller may change settings or take funds - Integer issues — mistakes in arithmetic, such as a number passing its maximum and rolling around unexpectedly. Solidity 0.8 adds built-in overflow checks, but unsafe logic can still cause losses
- Price manipulation — moving a thin market to fool a contract reading it. A lending or trading protocol may then value collateral or trades incorrectly
- Upgradeable proxies — the code behind an address can be replaced. An upgrade can fix a bug, but the upgrade controller remains a trust assumption
- Rug pull — a team removing value, changing the rules or abandoning a project. Users may be unable to recover what they put in
- Front-running / MEV — your pending transaction can be seen before it executes. Another participant may move first or reorder around it and worsen your result; the profit opportunity is often called MEV
- SWC Registry — a historical catalogue of known weakness classes. It is no longer actively maintained, so use current security resources too
A short checklist
Print it, or keep it in your head. Before approving anything:
Before you approve
- Which network? Testnet for Academy work, always.
- Which contract address? Verified against the official source — not a link someone sent you.
- What am I authorising? A transfer, an approval, or a signature?
- How much? A capped amount beats unlimited.
- Do I know this site is real? Bookmark, not search result, not DM.
- If this is wrong, what do I lose? If the answer is "everything", slow down.
Six questions, about fifteen seconds. It is the highest-value fifteen seconds in this handbook.
Worked example
A concrete drain, step by step. Nothing here is exotic.
| # | What happens | Where it went wrong |
|---|---|---|
| 1 | A "token airdrop" link arrives by DM | Reaching a DApp through a message |
| 2 | The site is a convincing clone | URL not checked against a bookmark |
| 3 | It asks to connect the wallet | Harmless on its own |
| 4 | It requests an unlimited approval for a token | The dangerous request |
| 5 | The user confirms it without checking the spender and amount — the actual mistake | The request is not read closely |
| 6 | The transaction confirms, but the balance stays unchanged. The user assumes nothing important happened and underestimates the permission they granted | No tokens moved, so the standing permission is missed |
| 7 | Minutes or months later, transferFrom drains the balance | Permission became effective when the approval transaction confirmed in step 6 |
Where this was actually preventable
Step 2 and step 5.
Step 2 is Week 0 Part 4 — bookmarks, not links. Step 5 is this page — read the request, notice "unlimited", cap or reject.
No sophisticated attack occurred. No cryptography was broken. Someone was helpful, then the user did not read one screen.
And notice the asymmetry: the attacker needed one careless approval; the user needed to be careful every time. That is why this is a habit rather than knowledge — you cannot look it up in the moment.
Keep this model handy
You now have a concrete model for reading token permissions: identify the spender, the amount, the submission path and how long the permission lasts.
Further exploration — optional, not assessed
- ethereum.org — Smart contract security — patterns and pitfalls
- SWC Registry — a catalogue of known weakness classes
- Ethernaut — OpenZeppelin's security wargame. Genuinely fun, entirely optional, and the fastest way to develop instincts
- Revoke.cash — check what you have approved. Worth doing once even with nothing at stake
Sources and attribution
- ethereum.org — Smart contract security — Reuse (CC BY 4.0), adapted
- ethereum.org — Security — Reuse (CC BY 4.0), adapted
- SWC Registry — Link, referenced only
- Revoke.cash — Link, referenced only
Changelog
ff0f4-feat(academy): finalize Foundation learning experienceona931f-docs(foundation): finalize beginner learning path and handbook UXon80d94-feat(foundation): complete Weeks 3-4 and add the visual layeron2d4b4-docs(curriculum): finalize Week 0-2 Foundation revisiononaed71-Bootstrap Blockchain@NTU Academy Handbookon