In cybersecurity, some of the first defenders are the software engineers who write and deploy code. AI can help security efforts “shift left” into the early stages of software development before vulnerabilities in those systems are ever reachable by attackers. AI—Large Language Models (LLMs) specifically— is a quickly evolving tool that is helping to harden code throughout the software vulnerability lifecycle at three key stages — discovery, patching, and exploitation.
AI is beginning to advance automation across the discovery (autonomously finding a vulnerability) and patching (autonomously generating a fix for the vulnerability) phases of the vulnerability lifecycle. While exploitation is primarily thought of as an attacker-only activity, it is useful for defenders in proving whether a vulnerability was properly fixed or not. That capability may be especially important for automating the verification and correctness of AI-produced vulnerability fixes. Each of these phases represents a distinct area of focus in computer science, centered on program analysis and characterized by many mathematically hard problems.
Over the past couple of years, engineers and researchers have begun applying LLMs to challenging software security problems, from memory safety to web application vulnerabilities, with mixed results. Within the software vulnerability lifecycle, a clear trend has emerged that includes integrating LLM-driven agents with traditional tools like fuzzers and static analysis to discover vulnerabilities and then using the models to generate and apply fixes directly where they can be deployed into software development and continuous integration pipelines.
An Introduction To Software Vulnerabilities and AI
A software vulnerability is often an implementation or design flaw in a program that can be exploited to compromise its security or functionality. These vulnerabilities can range from simple coding errors to complex issues involving countless potential program states, variables, and edge cases. The complexity of attempting to track these program states grows exponentially, and automated tools trying to cover all paths face combinatorial explosions. At a fundamental level, the discovery and exploitation of such issues is related to mathematically undecidable problems in computer science, such as the halting problem and Rice’s theorem, which show that no algorithm can decide non-trivial properties of arbitrary programs. For example, ensuring that no code path leads to an exploitable state is equivalent to solving an undecidable problem. These theories describe fundamental limitations for vulnerability discovery that persist even when applying AI. For LLMs, the challenges can be compounded further by practical constraints such as context window limitations and token-based computational costs.
A common criticism of large language models is that they lack creativity and mostly reflect content in their pretraining data. While these perceived limitations may slow adoption of AI in some domains, for some aspects of addressing software vulnerabilities, this limitation can be a strength. Most software security issues discovered each year are simply variants or instances of previously discovered patterns, rather than entirely new classes of vulnerabilities. In fact, discovering a novel vulnerability class is uncommon. The bulk of vulnerability discoveries are semantically similar to previously known and reported issues. Consequently, vulnerability researchers frequently focus on identifying new variants and unknown instances of known vulnerability types, a task that often requires pattern matching at scale.
The task of vulnerability discovery aligns well with the strengths of LLMs, which generalize patterns from pretraining data, making them well-suited for identifying new variants of well-understood vulnerability patterns. And there is no shortage of well-labeled data related to software vulnerabilities for fine-tuning and prompting strategies. However, advanced pattern matching with AI models alone is not enough to automate this effort; there are many other processes and tools involved throughout the vulnerability lifecycle. Current state-of-the-art models are quite capable of automating portions of those processes, such as by automating software builds, running traditional tools like fuzzers, analyzing their findings, and more.
Vulnerability Discovery
Automating vulnerability discovery has been an area of research for security engineers for decades. Existing approaches generally start by assessing the potential attack surface across millions of lines of code. LLMs have the potential to accelerate the process by narrowing the search to specific components that are more likely to yield results.
Traditional automated methods, such as fuzzing and static analysis, rely on brute-force or heuristic approximations to scale across large, frequently changing code bases. These approaches complement one another, have their advantages and disadvantages, but require significant human expertise to configure, execute, and interpret the results. LLMs may combine these approaches to improve code coverage or uncover vulnerabilities that one approach alone cannot.
Simpler non-AI methods involving basic pattern matching can also be effective for some vulnerability classes but often come with the tradeoff of higher rates of false positive or false negative results. However, not all vulnerability classes are created equal. Some vulnerabilities are difficult to identify with automated techniques, such as those that involve complex business logic or many state transitions between components. Others are more localized and can be discovered through simple pattern matching. When it comes to vulnerability discovery, there is no one-size-fits-all approach to automation.
Early research into using LLMs for vulnerability discovery used prompt engineering and Retrieval Augmented Generation (RAG) to identify vulnerability patterns in code without the use of external tooling or running the code. In addition to basic hallucination problems, those approaches demonstrated the limitations of these earlier models in understanding complex control flow graphs. Recent advances in models that reason through hidden ‘chain of thought’ tokens have shown significant gains in their ability to reason through code. These advances have shown remarkable accuracy in code generation, which creates significant opportunities to pair them with traditional vulnerability discovery tooling.
This agentic approach to combining traditional vulnerability discovery methods such as fuzzing, with the scale and automation LLMs provide, has demonstrated promising results. LLM-driven agents can autonomously generate and execute code that configures, builds, and applies traditional tooling to programs under test with tight feedback loops to improve their coverage and triage results with accuracy. With the data generated at each step, these models can refine their strategies for the next iteration. For example, LLMs can analyze a software library, generate new fuzzing harnesses that target its public APIs, create a data corpus to improve their initial code coverage, run the fuzzer, interpret the results, and propose fixes directly to the code under test. This can significantly speed up the vulnerability discovery phase and provide human experts with efficiency gains by automating tedious tasks.
Auto Fixing Vulnerabilities
For cyber defenders, discovering vulnerabilities is only one piece of the puzzle. Those vulnerabilities need fixes rolled out to production systems, devices, and endpoints as quickly as possible. This sounds like an easy task, but it is difficult in practice. LLMs that are capable of generating code and fixing vulnerabilities may be able to reduce the window of exposure to security vulnerabilities through automation. While reasoning models have demonstrated an incredible ability to generate small stand-alone programs, this comes with significantly less complexity than modifying code within an existing large and complex program. The difficulty of using LLMs to automatically fix vulnerabilities increases as the complexity of the program grows, just as the difficulty of discovering them does.
To properly fix a vulnerability, its root cause must be understood and fixed in a way that accounts for all possible code paths to reaching that vulnerability. Furthermore, the change introduced to fix the vulnerability must be considered within the broader context of the program. For example, if the patch is within a code path that is executed many times per second, it must not introduce significant performance overhead. The model must be able to reason through these components, understand this context, and generate correct code within these constraints.
Another common mistake to avoid is to “patch the exploit,” which means introducing a fix that breaks one of many possible vectors for exploiting the vulnerability but does not address its root cause. For a patch to be effective, it must introduce constraints that work on all possible edge cases to avoid introducing new issues or failing to address existing variants of the vulnerability present in the code. If a model relies too heavily on exploitation reasoning as a means for testing generated fixes, it may end up introducing an incomplete patch that can be trivially bypassed. Conversely, LLM-generated exploitation attempts can provide empirical evidence for the effectiveness of a patch in certain circumstances, but the absence of a successful exploit does not constitute a mathematical proof of security. Humans may still be needed to verify these fixes.
Exploitation
The exploitation phase of the vulnerability lifecycle is often misunderstood. The difficulty of crafting an exploit depends heavily on the characteristics of the target, including factors such as programming language, hardware, attack surface exposure, and communication medium. In some cases, these properties can simplify exploitation greatly. For instance, exploiting simple web application vulnerabilities, such as by command injections, often uses just a few lines of code. Those exploits typically do not require controlling intricate program states through multiple stages, and they are more common for higher-level languages like PHP, Python, or Java where failure is gracefully handled, allowing for additional exploitation attempts. As noted earlier, these vulnerabilities are frequently variations of one another, making exploitation strategies highly transferable. Exploitation strategies are widely available online and are included in LLM pre-training datasets, so state-of-the-art models are capable of generating exploits for these kinds of vulnerabilities. LLM-generated exploits for these vulnerabilities often require only minor modification from a human to ensure they run properly, gracefully handle errors, and fit into a larger toolkit. Automating the exploitation of these vulnerabilities with an LLM can lead to efficiency gains that allow humans to focus on more specialized tasks.
However, as exploit complexity increases, the model’s ability to generate precise and reliable exploits generally degrades. This is often the case with memory safety vulnerabilities in programs written in lower-level languages like C or C++. Exploiting those vulnerabilities often requires manipulating the program’s data structures, virtual memory layout, and program state to improve the exploit’s reliability. Exploit mitigations such as Address Space Layout Randomization (ASLR) or Control Flow Integrity (CFI) are likely to impose constraints at runtime but won’t be expressed in the vulnerable code itself. An LLM may need to analyze build scripts, and observe, inspect, and interact with the program at runtime before it is able to generate a successful exploit.
That does not mean AI has no role in developing these exploits, only that current state-of-the-art models are not capable of generating them in a zero-shot manner. Regardless of how simple or complex an exploit is, they are often built from composable, modular, and reusable components. For example, exploiting a use-after-free vulnerability in the core engine of a web browser, one of the most prevalent vulnerability patterns in such targets, requires several critical steps. These may include shaping the memory layout of the target to ensure exploit reliability and then restoring the application’s state to ensure it continues functioning seamlessly post-exploitation. Many of these steps are transferable in exploiting similar vulnerabilities within the same program; therefore, building reusable components creates a foundation for faster development of future capabilities.
This modularity underscores a practical application for LLMs in exploitation. Instead of writing these reusable components from scratch, models can offer uplift and efficiency gains by identifying which existing program components to leverage or by generating testing infrastructure to incrementally refine an exploit. This approach allows for more efficient development of reliable exploits while maximizing the utility of pre-existing components.
Looking Ahead
Agentic AI is already beginning to help scale vulnerability discovery by leveraging traditional tooling. The process of analyzing the root cause of a vulnerability closely aligns with the requirements for developing effective and accurate patches, as both aim to identify and constrain all possible pathways and variants of the vulnerability. Automated vulnerability fixing, in particular, depends on this understanding that the fix comprehensively addresses the underlying issue without leaving exploitable variants in the code. Exploitation requires a deep understanding of program semantics to manipulate the target’s behavior. Thus, the interplay between vulnerability root cause analysis, auto fixing, and exploitation highlights the importance of rigorous semantic analysis and scalability across the software vulnerability lifecycle that AI may be uniquely positioned to assist with.
As powerful as agentic AI approaches to the vulnerability lifecycle are, they are still limited by the capabilities of the traditional tools they are driving. Even an AI-driven fuzzer can still only find specific types of vulnerabilities. It is limited in its ability to tell us about the broader attack surface of a program, or reason through the kinds of business logic vulnerabilities that only manifest when the application interacts with other systems. As reasoning models advance and computing costs come down, AI models will become more important throughout the vulnerability lifecycle. While human oversight is still essential for validating highly complex or safety-critical codebases, this trend is likely to grow in the coming years.