Introduction
Every software project eventually accumulates code that has never been covered by a test. When a security vulnerability emerges, the instinct is to patch quickly, but without a safety net, a well-intentioned fix can silently break features that have worked for years. This article explores why untested code is a ticking clock, how AI-assisted changes accelerate the risk, and what every team should do before merging a patch.
What Happened
In September 2026, Microsoft released KB5002914, a security update for Excel that quietly disabled paste operations and AutoFill across versions ranging from Excel 2016 to Microsoft 365 Apps. Users reported cells stuck mid-selection, blinking borders, and a non-responsive Escape key. The issue traced back to conditional formatting logic that had never been exercised by a test. Because the module had shipped two decades earlier without a verification suite, the patch reached production with no one knowing how the clipboard code would react. The fallout took more than a hundred forum replies and a secondary fix (KB5002665) before the root cause was officially acknowledged.
Why This Matters
The Excel incident isn't an outlier—it's a pattern. Any stable product shipped into untested territory faces the same blind spot. AI coding assistants can generate a diff in seconds, but they can't know which edge cases, corner cases, or decades-old code paths will break when the surrounding logic has never been asserted. A patch that compiles and looks plausible can still alter behavior users rely on daily, eroding trust faster than any new feature can build it. When verification isn't automated, the gap between edit and regression widens, and users become the unwitting testers.
Key Takeaways
- Write a characterization test that records the module's current behavior before any AI-driven change touches it.
- Find a seam in the code where the patch can be routed through an entry point rather than editing the untested core directly.
- Ask the AI to draft missing tests for the exact module you're about to patch, then review every assertion before committing.
- Run the full regression suite and any acceptance tests before and after the patch; reject any fix that doesn't leave every existing test passing.
- Scope the change to the smallest possible edit that closes the security hole, and prevent the AI from cleaning up nearby legacy code in the same commit.
- Never authorize the AI to change functional behavior while closing a security hole; if it must, stop and require human sign-off.
- Add every new characterization test to the pipeline so the same regression never depends on a user reporting it again.
- Ship to a small canary segment first when possible; a blind spot in legacy code should surface on a fraction of users, not all of them.
- When a vulnerability is already public, patch everyone immediately but lean on characterization tests to catch regressions post-deploy.
- A passing test suite replaces a shrug and a hope with a specific, checkable claim about what still works.
Conclusion
Untested legacy code isn't inevitable just because a system is old. Every long-lived product contains modules that have never been verified, and every untested patch is a gamble with user trust. The solution isn't slower releases—it's building seams, writing characterization tests, and demanding that AI-generated changes pass the same verification bar a human would. The next time an AI drafts a security fix, make sure the first thing it triggers isn't a user complaint, but a green regression suite.




Discussion
Join the conversation
Thoughtful reactions, questions, and follow-up ideas help shape the next story.