← All articles

What Building a Patented Vulnerability-Scanning System Taught Me About 'AI for Security'

A few years ago, working within Dell's engineering organization, I was part of a team that designed and patented a system for automated code vulnerability detection and remediation (US Patent 11,514,171). The pitch was simple: scan committed code, find known vulnerability patterns, and — where confidence is high enough — fix them automatically as part of the CI/CD pipeline, before a human ever has to context-switch into a security review.

The patent itself describes the plumbing: a code analyzer, a language detector, a cleaning step that strips out comments and noise, a conversion into an intermediate representation, and a matching engine that compares that representation against a corpus of known-vulnerable snippets using similarity scoring. What I want to write about isn't the plumbing. It's the three things that determined whether this kind of system was actually useful versus actively annoying — and they're the same three things I see teams get wrong on every "AI-powered" tool that's launched since.

The model is not the product — the corpus is

It's tempting to describe a system like this as "an ML model that finds vulnerabilities." That framing undersells the part that actually does the work. The matching model — comparing a code fragment's vector representation against known vulnerable snippets via cosine distance — is genuinely the easy part. Off-the-shelf similarity search has been solved for years.

The hard part, and the part that determines whether the tool is trustworthy, is the knowledge base: the corpus of vulnerable code fragments paired with verified fixes. Get that corpus wrong — stale entries, fixes that don't generalize across frameworks, patterns too narrow or too broad — and the "AI" part doesn't matter. You'll either miss real vulnerabilities or, worse, confidently apply a wrong fix.

This is the pattern I'd point to for anyone evaluating a vendor's "AI security" claim today: ask what the knowledge base is, who curates it, and how fast it updates when a new CVE class emerges. If the answer is vague, the model quality is a distraction from the real question.

Automation needs a confidence threshold and an honest failure path

The system didn't just flag vulnerabilities — on a high-confidence match, it would apply the known fix, rebuild, and push through staging automatically. That's a meaningfully different design decision from "flag and let a human decide," and it only works if you're honest about two things:

  • What "high confidence" actually means numerically, and how you validate that threshold isn't quietly drifting as the corpus grows.
  • What happens on the failure path. If the automated fix doesn't build cleanly, the system routed the issue to a developer for manual resolution — and critically, whatever the developer did next fed back into the corpus. The failure path wasn't a dead end; it was training data.

A lot of "automated remediation" tooling skips that second part. It'll auto-generate a fix, and if it's wrong, the burden of noticing and correcting it falls entirely on the developer with no mechanism for the system to learn from that correction. You end up with a tool that's exactly as smart on day 1000 as it was on day 1 — which, for a security tool specifically, is a slow way of training your engineers to stop trusting its suggestions.

A simplified version of the decision logic looks roughly like this:

def remediate(code_fragment, corpus, threshold=0.92):
    vector = embed(code_fragment)
    match, distance = corpus.nearest_neighbor(vector)

    if distance >= threshold:
        fixed_code = apply_fix(code_fragment, match.solution)
        if build_succeeds(fixed_code):
            return Remediation(fixed_code, auto_applied=True)
        # automated fix didn't build — don't guess further,
        # hand off with full context instead of a silent failure
        return escalate_to_developer(code_fragment, match, reason="build_failed")

    # below threshold: no confident match, human review required
    return escalate_to_developer(code_fragment, match=None, reason="low_confidence")


def on_developer_resolution(code_fragment, resolution):
    # this is the part most "AI-powered" tools skip:
    # every human correction becomes a corpus update,
    # not just a closed ticket.
    corpus.add(code_fragment, resolution.fix, verified=True)

That feedback loop — on_developer_resolution actually writing back into the corpus — is unglamorous, and it's also the entire reason the system got better over time instead of just staying at whatever accuracy it shipped with.

Static analysis was never the bottleneck

The last thing this project taught me: teams already have static analysis tools. SAST scanners, linters, dependency checkers — most enterprises are drowning in vulnerability findings, not starved for them. The bottleneck was never detection. It was triage and remediation — someone has to read the finding, understand whether it's a real risk in this context, know the correct fix, apply it, and verify it didn't break anything.

Any "AI for security" tool that focuses purely on finding more issues, faster, is optimizing the part of the pipeline that was never the constraint. The systems worth building — and the reason I still think about this architecture years later — are the ones that close the loop from finding to verified fix, and get measurably better every time a human has to step in.