Pre-Deployment Security Fails When Teams Review Functions but Not Release Paths
Most launch checklists ask whether the contracts were audited. The better question is whether the release path can safely change production truth.
Establish the problem with technical depth
The most expensive security decisions in Web3 are usually made before mainnet, but not in the place teams like to point at. They are made in the architecture around the contracts: who can upgrade them, who can list new markets, who can point to a new oracle, who can expand approvals, and how fast any of that can happen once the system is live. CTOs experience that as "small" launch exceptions. Investors experience it later as a loss that looked operational until it became existential.
LI.FI is a clean example because the failure window was so short. In LI.FI's July 18, 2024 incident report, the team says that on July 16, 2024, shortly after adding a new smart-contract facet, the protocol suffered a breach that affected 153 wallets and led to an estimated $11.6 million in stolen funds. The report says the newly added facet let callers make arbitrary external calls because a validation check that existed elsewhere was missing in this deployment. That is a release path putting unsafe authority into production within minutes.
Penpie shows the same category from a different angle. In Penpie's September 3, 2024 post-mortem, the team says an attacker stole 11,113.6 ETH, roughly $27.3 million, by exploiting a reentrancy issue in batchHarvestMarketRewards(). Reentrancy means external code regains control before your contract finishes settling its own accounting. Penpie says the attacker registered a fake Pendle market and used flash-loaned deposits to manipulate reward accounting during the harvest flow. The lesson is not just "watch for reentrancy." It is that a live protocol is only as safe as the production changes it allows and the assumptions those changes silently carry.
This is why pre-deployment security is badly understood. Teams talk about it like a one-time quality gate before launch. In reality, it is where you decide whether post-launch change will be survivable. If the protocol can list a market nobody modeled, ship an upgrade nobody replayed, or hand a privileged role to an operational path nobody stress-tested, then the exploit surface was designed in before users arrived. That matters because most nine-figure failures do not come from syntax errors. They come from production truth moving outside the review boundary.
The mechanism, the mistake, the misunderstanding
The mechanism behind these failures is not mysterious. Teams review functions and under-review release paths.
A release path is every code path and operational step that can move the live system from one truth state to another. It includes proxy upgrades, initializer values, signer workflows, market registration, oracle configuration, allowlists, router changes, emergency powers, deployment scripts, and the permissions that authorize those actions. Those are not "operations around the contracts." They are part of the contract system because they can change what the system is allowed to do with user money.
OpenZeppelin's upgradeability guidance exists because upgradeable contracts do not behave like immutable ones. Once a proxy sits between users and logic, review has to expand beyond whether one function body looks correct. You have to care about initializer safety, storage layout compatibility, upgrade authorization, and whether the new implementation widens power in ways the previous threat model never covered. OpenZeppelin's access-control documentation makes the same point from the permissions side: roles can mint, freeze, vote, or otherwise change the system's effective rules. If a role can alter a money-moving path, that role is part of your attack surface.
The mistake is treating those surfaces as secondary. Teams call them launch tooling, admin plumbing, or just governance. That language is how dangerous changes get smuggled past the security process. A new market-registration path feels smaller than core accounting logic. A signer workflow feels like process, not product. Then the exploit lands through the "smaller" thing because that was the part nobody modeled adversarially.
The misunderstanding is even more basic: "audited" does not describe a protocol. It describes a past review event with a scope, a commit range, and a threat model. It does not automatically describe the next upgrade, the next signer rotation, the next dependency, or the next emergency change done under pressure. LI.FI and Penpie both make that point. In each case, the dangerous production path was not hypothetical. It was a reachable path the live system allowed after real operational decisions.
That is why so many launch checklists are theater. They verify whether the code compiles, whether tests pass, whether an audit PDF exists, and whether the team can click deploy. They do not verify whether the release machinery can install new trust assumptions that the engineering team has not exercised. Pre-deployment security fails the moment it asks, "Is the contract ready?" instead of, "Can this production system change safely after we ship it?"
What good looks like
Good pre-deployment security starts by classifying releases, not just contracts. If a change touches upgrade authority, external calls, collateral logic, reward accounting, market registration, oracle sources, or privileged roles, it belongs on a security review track. Every such change can redefine the conditions under which the protocol fails.
Good also means writing invariants before declaring the system launchable. Foundry's invariant testing guide describes invariants as properties that should always hold regardless of the sequence of actions taken. That is the right frame for DeFi. Engineers should not stop at "deposit works" or "withdraw works." They should encode truths such as liabilities cannot outrun realizable assets, reward claims cannot exceed rewards actually accrued, and upgrade authority cannot bypass the expected control path. If those statements are not machine-checked, the team is still arguing about security in prose.
Fork testing needs to be part of the launch gate too. Foundry's fork-testing guide is explicit that fork testing lets teams run against real chain state without touching a live network, which is essential for testing integrations with existing protocols. A fork is just a local copy of onchain state at a chosen block. That matters because many failures only show up when you exercise the real token behavior, real liquidity conditions, real approvals, and real external contracts your protocol depends on. If a market listing, router integration, or deployment script has never been rehearsed on a fork, the team is shipping assumptions, not evidence.
Privilege should be treated as inventory, not background noise. Before launch, a protocol should be able to say which roles can upgrade logic, list markets, pause functions, change fees, move treasury assets, swap dependencies, or alter oracle inputs. Then it should prove why each one exists. If a temporary power is still hanging around because removing it was inconvenient, that is not flexibility. That is unpriced authority.
The deployment path itself should be rehearsed as if it were treasury code, because it is. That means decoding upgrade calldata independently, checking storage compatibility before shipping new implementations, validating initializer arguments, and reviewing role-grant transactions. Teams that only review Solidity but not the concrete transaction sequence that changes production are still leaving the highest-leverage step to hope.
Finally, good looks observable. The first live block after launch or after an upgrade should not be the first moment the team wonders whether the system still matches its assumptions. Role grants, implementation changes, newly registered markets, pause actions, and unusual value movements should all be visible quickly enough that humans can intervene before a post-mortem exists. Security is not finished when the deployment succeeds. It is finished when the team can prove the deployed truth still matches the reviewed truth.
ChainShield's angle
ChainShield's view is that most Web3 teams still aim security effort at the wrong artifact. The artifact is not the code snapshot. It is the live change surface.
That is why we care more about diff-aware review, release-path verification, privilege mapping, and replayable evidence than about one more static document saying somebody looked at the code once. The job is to reduce the gap between what the team believes production can do and what production is actually allowed to do after the next change.
For founders and investors, that is the due-diligence upgrade that matters. Ask what can change the system, who can approve it, how it is rehearsed, and what evidence proves the review covered the exact path that is about to go live. For CTOs and Solidity engineers, stop treating pre-deployment security as audit prep and start treating it as release engineering for adversarial systems.
If your launch checklist still centers on whether the contracts were audited, you are reviewing the past. The protocols that survive are the ones that can show their release path is as rigorously designed as their Solidity.
ChainShield Discovery Runs are designed to identify high-risk issues quickly, validate what matters, and give engineering teams a faster path to remediation.
Request Security Quote