Most AI coding tools are very good at helping developers write code.
But I wanted to explore a different question:
Can AI help developers find the edge cases and security problems they didn't think about?
That question led me to build EdgeGuard, an open-source VS Code extension designed to investigate code from an adversarial perspective.
The idea is simple:
Try to break the code before production does.
But when I first tested the idea against real security benchmarks, I discovered a problem.
The AI was too optimistic.
And OWASP exposed it very quickly.
I started testing EdgeGuard against the OWASP Benchmark for Java.
One of the first things I noticed was surprisingly simple.
Given code like this:
String param = request.getParameter("id");
String bar = DatabaseHelper.doSomething(param);
String sql = "SELECT * FROM USERS WHERE ID='" + bar + "'";
The LLM could see the untrusted HTTP input.
It could see the SQL construction.
But it couldn't see what doSomething()
actually did.
So it made an optimistic assumption:
"This is probably an internal helper that sanitizes the input."
And the result could be:
SAFE
even though the data was still flowing into a SQL sink.
This was exactly the kind of false negative I wanted EdgeGuard to find.
The problem wasn't that the model couldn't understand SQL injection.
The problem was that the model was filling in missing information with an optimistic assumption.
I changed the investigation strategy.
Instead of sending raw code and asking:
"Is this vulnerable?"
EdgeGuard now provides explicit security assumptions and asks the model to preserve taint unless there is evidence that it has been sanitized.
One important rule became:
If tainted data enters an unknown function, treat the data as still tainted unless there is evidence that the function sanitizes it.
The investigation also became evidence-oriented instead of relying on a simple SAFE
or VULNERABLE
classification.
For example:
That small change made a big difference.
The AI was no longer being asked to guess what an unknown function probably did.
It had to reason from the available evidence and follow explicit security assumptions.
Finding a potential vulnerability in one function is one thing.
Doing it across thousands of functions is another.
Large projects contain enormous numbers of methods that simply aren't interesting from a security perspective:
get()
set()
ToString()
Equals()
simple CRUD methods
data mapping
utility functions
Sending all of them to an LLM would be wasteful.
It would also create two immediate problems:
API rate limits and API cost.
My philosophy has always been:
Start with the simplest solution, and only add complexity when the simple thing breaks.
So I didn't want the LLM to analyze everything.
I added a local Static Risk Screening stage that runs directly inside VS Code.
Before making an API call, EdgeGuard parses the code locally and looks for characteristics that make a function worth investigating.
For example:
The local stage acts as a filter.
Instead of:
7,000 functions
β
LLM
β
$$$$$$$$$
the architecture becomes:
7,000 functions
β
Local Static Screening
β
High / Medium Risk
β
LLM Investigation
β
Evidence + Verification
This makes the LLM a reasoning engine, rather than the first line of analysis.
I wanted to know whether this architecture would actually work at project scale.
So I loaded the entire OWASP Benchmark Java project into VS Code and triggered a workspace scan.
The scan discovered:
The local screening stage first filtered the code and identified functions that deserved deeper investigation.
The LLM then focused on the higher-risk candidates instead of blindly processing every function.
In this test, EdgeGuard reported:
2,145 potential defects
The findings included security issues such as:
The important part for me wasn't simply the number of findings.
It was that the architecture could move from:
one function β one LLM request
to:
whole workspace β local screening β targeted AI investigation
without turning every method into an API call.
I also wanted EdgeGuard to work beyond Java.
So I tested the architecture against projects in three different ecosystems:
OWASP Benchmark
OWASP Juice Shop
Microsoft eShopOnWeb
This introduced another problem.
Java, C#, and TypeScript have very different:
I didn't want language-specific parsing logic leaking into the investigation engine.
So I separated the language context layers.
The architecture became roughly:
EdgeGuard
β
Investigation Engine
β
βββββββββββββΌββββββββββββ
β β β
Java C# TypeScript
Context Context Context
β β β
AST AST AST
The investigation logic can therefore remain shared while the language-specific context stays isolated.
This became an important design principle:
Share the investigation logic. Isolate the language-specific context.
At this point, I realized that simply generating a vulnerability report wasn't enough.
An AI can say:
"This might be vulnerable."
But what I really want is:
"Here is how you can reproduce it."
So EdgeGuard is designed to go beyond detection.
For potential vulnerabilities, the agent can attempt to construct counterexample inputs and generate runnable verification tests.
Depending on the language, that can mean:
The goal is to move from:
AI says:
"This might be vulnerable."
to:
AI hypothesis
β
Counterexample
β
Generated test
β
Execution
β
Evidence
The principle is:
Evidence over assumptions.
Building EdgeGuard changed how I think about AI-assisted code analysis.
The difficult part isn't simply getting an LLM to understand code.
The difficult part is controlling what the model is allowed to assume.
If an unknown helper is assumed safe, a vulnerability can disappear.
If every function is sent to an LLM, the system becomes expensive and difficult to scale.
If language-specific context is mixed together, supporting multiple languages becomes increasingly fragile.
So the architecture ended up combining three different approaches:
Static analysis for fast deterministic screening.
LLM investigation for reasoning about complex code paths.
Verification for turning hypotheses into evidence.
None of these approaches is perfect on its own.
Together, they are much more interesting.
EdgeGuard is an open-source VS Code extension, and it is still evolving.
The project is available here:
GitHub: https://github.com/phucphungbk/edgeguard
The idea behind EdgeGuard is deliberately simple:
Don't just ask AI to write your code. Ask it how your code could fail.
If you work with security-sensitive applications, large codebases, or legacy systems, I'd love to hear how you approach this problem.
How do you find edge cases?
How do you deal with false negatives in automated code analysis?
And most importantly:
How do you prove that an AI-generated security finding is actually real?
I'm building EdgeGuard to explore those questions.
Feedback, bug reports, benchmark results, and architectural criticism are all welcome.