{"slug": "web-app-pentesting-in-the-ai-era", "title": "Web App Pentesting in the AI Era", "summary": "A web application pentester at IncludeSec reported that after three months of hands-on testing, both frontier and open-weight large language models added real value to vulnerability analysis, but results depended on aligning model, harness, and task, and outputs still required review by a skilled security professional to handle false positives and negatives. The post distinguishes between the model, inference engine, and harness, noting that the harness provides memory and tool execution, and that models do not update during use.", "body_md": "**What 3 months of hands-on testing with frontier and local models actually showed.**\n\nAI is understandably a prominent topic in all forms of media and conversation right now. As such a hot topic, the coverage has gotten very noisy. Hyperbole abounds and it’s hard to find grounded reality in the chaos. This post aims to provide a perspective from a web application pentester who just wants to know how things work. Keep in mind this post is not intended to empirically demonstrate whether various models and harnesses are superior to one another. Instead, it’s an accounting of my personal foray into AI-assisted vulnerability analysis. If you’re a web application security tester or someone who hires web application security testers, hopefully this will help you calibrate your gauge for the utility of AI systems and the value of the skilled professionals who use them.\n\nFirst, let’s define the three main components of an AI system built around a large language model (LLM). They are often conflated and it is important to remember what each part does.\n\nThe model – An AI model is a large set of numerical parameters organized according to a particular architecture. These parameters are stored as data. When the model is loaded into an inference engine, the engine performs computations using the parameters to generate output. The model can be thought of as the brain of an AI system, but it cannot do anything on its own. It requires an inference engine to receive input and generate output. Models vary widely in size, capabilities, resource requirements, and intended uses. Some are proprietary, and available only through a vendor’s services or APIs. Others are released publicly as open-weight models, allowing others to download and run them themselves.\n\nThe inference engine – Like database software that enables interaction with database contents, the inference engine is software that provides an interface to the model. The inference engine interface is read-only. The model is not updated during use (i.e. the brain does not form new memories). Separate software exists for model modification. AI systems might appear to learn and remember things as you use them, but that is a property of the harness, not the model or the inference engine. So far, there has been much less differentiation between inference engines compared to models or harnesses, so this layer gets relatively little attention. It’s a necessary component, but the least interesting of the three.\n\nThe harness – This is the code (and any other infrastructure) built around the inference engine. Memory of previous messages, tool execution, and initiation of all actions comes from the harness. A harness could be a very simple script or a massive application. A lot of good and bad could exist in a harness, just like code without AI models.\n\nThe capabilities of AI systems have clearly improved in the past year. My colleague at IncludeSec described his experience with[ CTFs in the AI Era](https://blog.includesecurity.com/2026/04/ctfs-in-the-ai-era/). In his post, he acknowledges the differences between CTFs and real-world pentesting, but the changes from 2025 to 2026 indicated an advancement that warranted attention. The immediate question of “How will this apply to our actual work?” quickly split into two branches of exploration: “How capable are frontier models of finding vulnerabilities in web applications?” and “How capable are open-weight, smaller models of doing the same?”\n\nMy experience found that models both large and small were capable of adding real value to a security review. Results depend on a three-way alignment of model, harness, and task. In addition to optimizing this alignment, the output in the best cases still requires review from a knowledgeable web application security professional to handle false positives and false negatives.\n\nOptimizing AI use for security consulting is not as simple as choosing the largest model and asking it to “Find all the vulnerabilities and don’t hallucinate.” There are many models, providers, cost considerations, client data-handling limitations, harnesses, hardware variations, deployment parameters etc. Additionally, all of those variables are changing rapidly. There are published benchmarks which provide some indicators of capability, but none of them align completely across each of the variables for any individual’s real circumstances.\n\nIn the descriptions that follow, all coding and testing was performed between April and July 2026 against the model versions named.\n\n**Getting Hands-On**\n\n**One Shot**\n\nTo bite off a chunk that I could confidently chew, I started with a relatively easy question: “Can AI get a passing score on the hacking challenge we developed for Include Security’s applicant evaluation process?” Our challenge is a time-limited source code-assisted penetration test of a small web application. The application contains a large list of (mostly) intentional vulnerabilities which are known and documented internally. The vulnerabilities range from low to critical in severity and from obvious to obscure in discoverability. Those traits determine point values for each vulnerability and applicants must score above a certain threshold to be considered for employment. This internal application offered a few immediate benefits as the starting point: it is a web application (our most common type of target), I know the list of vulnerabilities in it with high confidence (easier to judge the results), and the source has not been released publicly (I don’t expect it to be in any model’s training data).\n\nI started with the simplest, laziest approach: just ask Claude Code for the vulns. At the time, neither the recently released[ /security-review Claude Code skill](https://support.claude.com/en/articles/11932705-automated-security-reviews-in-claude-code#h_e1354dfce5), nor my own “Find the security vulnerabilities in this application code” prompt found enough findings to pass the test. They found real vulns with minimal noise (there were no false positives at this point) but both simple approaches stopped well short of the complete list of high-risk vulns in the app. In addition to identification, our challenge requires the participant to demonstrate exploitation of each recorded finding in the form of HTTP request/response pairs and to quote the relevant code. The one-shot approach did not obtain the evidence required to prove the findings and score full points for the vulnerabilities in the challenge.\n\n**Building a Simple Harness**\n\nInspired by[ Nicholas Carlini’s presentation at [un]prompted](https://www.youtube.com/watch?v=1sd26pWhfmg), I wrote a simple harness. Two primary challenges needed to be addressed: thoroughness and validation.\n\nI observed that lazy use of inference engines results in lazy work performed by the model. Even though Opus 4.7 was clearly capable of finding vulnerabilities and there were straightforward vulnerabilities left to find, the simplest prompts led to the model stopping early. Either a person or a script needs to keep prodding it to make it keep working. Carlini’s solution addressed this by executing a loop of code that prompted the model to review each code file individually rather than making a single request to review the code repo as a whole. As he acknowledged, this is still not optimal, but it is a step forward and an example of how specificity improves inference outcomes.\n\nAfter the thoroughness problem, there’s the validation problem. In many cases, the model claimed to have proof of the exploit while the provided proof was clearly incomplete. Sometimes no proof was returned at all, but the model confidently asserted that the vulnerability was real and had been exploited. For validation, additional code was added to insist on repeatable proofs-of-concept for accepted vulns. Execution-grounded proof (a payload that can be replayed against a running target) is more trustworthy than anything a model merely reasons its way to. In the same vein, I’d consider good unit tests to be more reliable than AI code review (whether the concerns are security-focused or not).\n\nThat principle shows up in my development work too. I’ve gotten into the habit of using Codex with GPT-5.5 to review code that Claude Code writes with Opus 4.8, and it routinely closes fairly obvious gaps (although some still get through). The checker doesn’t have to be a different model; it has to be a different job. It could be a test suite, a replayed payload, a second pass with a different prompt; anything but asking the thing that produced the work whether the work is good.\n\nIn a short time, with a simple vibe-coded Python script, the results improved significantly. Opus was now identifying and documenting enough vulnerabilities in the target application to achieve a passing score on the assessment. In 51 minutes of runtime, the simple harness used $29 of Anthropic API tokens to beat the test. With similar coaching of Claude Code, the same results could be obtained using the more economical $100 monthly subscription. Our challenge was built to measure how a person reasons through an unfamiliar application, and that measurement doesn’t survive contact with an unsupervised model. For now, we prohibit AI during evaluation while we work out the long-term answer.\n\n**Swapping Frontier Models**\n\nHaving had some success with Opus, I was curious to see how the results would compare with GPT and Gemini. The harness and target application were unchanged, but the harness instead called GPT-5.4 and then Gemini 3.1 Pro. The GPT run quit after 12 min and used $5.00 to find half of what Opus 4.7 found. Gemini ran for 13 min, cost $9.19 and found only one of the ten vulnerabilities that Opus found. This should not be taken as a ranking of frontier models. The models behaved so differently that I attribute the discrepancy in outputs more to the harness than to each model’s overall capability. This notion of matching harness to model was reinforced by my later testing of open-weight local models. I did not attempt to optimize the use of each model. My motivation was driven by an interest in what I could do with AI, not to benchmark the models. Later, I used[ Metis](https://github.com/arm/metis) with GPT-5.5 to code review the test application and it found all of the high and critical risk vulnerabilities.\n\n**Trading Power for Privacy: Testing With Local Models**\n\nNot every client is comfortable sending their source code to hosted models. Using frontier models for client engagements is determined by each client’s data handling requirements. Some embrace online models. Some forbid them. Due to inconsistent access to frontier models, and the fact that every frontier experiment costs money, I decided to explore what I could do with my own consumer hardware.\n\nI own an[ ASUS Ascent GX10](https://marketplace.nvidia.com/en-us/enterprise/personal-ai-supercomputers/asus-ascent-gx10-1tb/) with 128 GB of unified memory. It’s more powerful than my laptop, but not extreme in terms of cost or capability. I attempted to reuse the harness that had successfully found vulnerabilities when paired with Opus. The harness was executed again using a variety of locally-hosted models (mostly Qwen variants, but also GPT-OSS, Llama, and Gemma). The local models all fell well short of the Opus results. Qwen 3.6 showed the most promise, so I began optimizing the harness to get the most out of Qwen 3.6. The harness got larger, more detailed, and permitted more rounds of tool calls than were afforded to Opus in the original harness. Eventually, the extended harness driving Qwen matched the Opus results but with a roughly 7 hour run time (as compared to 51 minutes with Opus). I tried different models, different inference engines, script updates, and configurations and did not find any working solutions to bring down the run time while retaining quality results. There are tradeoffs, but my most important conclusion was that locally hosted models are capable of making significant contributions to web application assessments.\n\n**More Isolation; SAST Only**\n\nEven with a local model, dynamic testing is still an avenue paved with anxiety. Since my initial draft, several incidents have been publicized where testing harnesses “escaped” containment and hacked systems they were not authorized to test. Our team most often tests client applications over the internet. We cannot assume that every client will be prepared to provide a fully functional copy of their system in an air-gapped virtual environment. So, we need to offer a solution that takes advantage of the new model capabilities, but can avoid rogue agent incidents with certainty.\n\nMy next pivot was to convert the grey box pentesting harness into a SAST appliance. By restricting the functionality to only source code review, the AI system can be restricted to an environment with no external network connectivity to assuage fears of rogue AI hacking out-of-bounds. The resulting harness is internal-only for now but might be released as an open-source project in the future.\n\n**Phased Tool Architecture**\n\nThe SAST harness runs as four discrete phases:\n\n**Generate.** A forced pass over every in-scope file produces candidate findings.**Enrich.** Each candidate becomes a brief with four fixed sections: the claim, the evidence, why it might be a false positive, and a proof-of-concept outline.**Refute.** A separate, higher-precision model reviews each brief as a cold second opinion and attempts to dismiss candidate findings (False Positive reduction).**Export.** The briefs are written out as a shareable tree for review outside the tool.\n\nThe export tree is plain and self-describing: briefs are filed by whether the refutation step could dismiss the finding and then by impact, with a Markdown and a machine-readable JSON copy of each candidate, plus an index of every finding and a README explaining the structure and what each refutation status means. Candidates the automated skeptic could not dismiss are ordered first. Reading results requires neither the tool nor a GPU, so team members review in their own tooling instead of being pushed through an interactive flow, and the same tree carries the findings onward to the report.\n\nAcross all five phases the model has no tool calling: it is given source code, returns text, and the harness parses that text into a stored record. There is no tool-call loop, no shell out, file-writing, or network tool available to the model. The proof-of-concept outline in a brief is written for the consultant to judge rather than executed by the tool. The review reads source code only: it never runs the client application, never sends traffic to it, and never attempts exploitation.\n\nThe benefits of the phased design:\n\n**Every candidate faces an explicit attempt at refutation** before a consultant spends time on it, and the surviving reasoning is recorded rather than hidden.**Every phase writes inspectable output to disk.** Work can be checked, scoped, or stopped at a boundary rather than disappearing into one opaque run.**Coverage is mechanical, not model-directed.** Generation is forced per file, so the model cannot quietly skip a file it found uninteresting, and what was in scope stays auditable.**One model in memory at a time**, which is what allows a larger, more precise model to do the refutation step on modest hardware.\n\n**Quantization**\n\nThe resulting SAST harness uses Qwen 3.6-35B-A3B at 4-bit (Q4_K_M)[ quantization](https://mljourney.com/quantized-llms-explained-q4-vs-q8-vs-fp16/) to generate candidates (potential vulnerabilities) with the same type of loop: “Find vulns in this file.” Candidates are written to files as they are identified. When candidate generation is complete, the harness drives another pass over the documented findings to refute invalid candidates (trim false positives). Many models were tried for each half of the work. Qwen 3.6-35B-A3B performed the best. Different quantizations of this model were then tested. 8-bit quantization (Q8) didn’t improve generation over Q4. Q2 degraded it. The full bf16 did not improve refutation beyond what the Q8 achieved. Given these results, the harness currently performs candidate discovery with the Q4, then ejects the Q4 model to perform the refutation phase with the Q8.\n\n**Cross-File Context**\n\nFor additional test cases that could be easily evaluated, five additional intentionally vulnerable apps were downloaded to build a test suite. The test suite included: our internal evaluation app,[ govwa](https://github.com/0c34/govwa) (Go),[ juice-shop](https://github.com/juice-shop/juice-shop/) (JS/Node),[ NodeGoat](https://github.com/OWASP/NodeGoat) (JS/Node),[ PyGoat](https://github.com/adeyosemanputra/pygoat) (Python),[ WebGoat](https://github.com/WebGoat/WebGoat) (Java).\n\nAgainst this set of known vulnerabilities, I iterated on the harness to coax out more true positives without an explosion of false positives. Forcing a pass over every file ensures each one is reviewed, but achieving source code coverage does not necessarily result in fully understanding the application. A model reading one file at a time knows that file; it does not know the entire application.\n\nI tried to provide the model with that understanding to see if it either improved initial candidate generation or the refutation of false positives. A separate code-analysis application produced cross-file traces for each candidate and I fed those traces to the model alongside the code. It made no difference to the eventual output. A model analyzing the code for vulnerabilities with two different sources of cross-file context performed no better than a model that had not been supplied with any context at all. On the Go targets, where semantic taint should have the best shot, I went further and ran the supporting analysis tool at full semantic power, with language servers resolving types across the project. That made no difference either. The model identified real vulnerabilities and refuted candidates at the same rate whether or not it could see the surrounding code.\n\nWhat did work was cheaper and dumber. Telling the model that certain core language methods were potential sinks for path traversal recovered a real bug it had missed on every previous run. That knowledge needs no external analysis application at all. It was not free: the added guidance also shifted the model’s output on classes I had not mentioned. The harness output gained one real bug for a couple more false positives. The harness gained nothing from my attempts at code comprehension. More true findings came from telling the model what to look for.\n\nThere was a balancing act here. I didn’t want to hard-code the harness to beat the test. When providing direction on potential tainted sources or vulnerable sinks, the intention was only to add guidance that would apply consistently to that language/framework and future applications. There’s nothing to be gained by telling the model details that overfit the harness to Juice Shop.\n\n**Open Source Harness Trials**\n\nThe output of the harness was compared to free non-AI static analysis applications and several open-source AI harnesses. The non-AI baseline was gosec and semgrep. The two general-purpose AI harnesses I tested against the suite on a local model were[ ai-sast](http://github.com/rivian/ai-sast) and Metis. The pool was smaller than I wanted. Some harnesses have no local path:[ Shannon Lite](http://github.com/KeygraphHQ/shannon) drives the Claude and Codex CLIs,[ Loupe](http://github.com/project-loupe/loupe) is frontier-only, and[ OpenAnt](http://github.com/knostic/OpenAnt) is hardcoded to the Anthropic API. Others hit walls on the larger targets: ai-sast was intolerably slow on a local model as the applications grew, and Metis did not support Java, so WebGoat was not possible for it.\n\nAcross the test suite, my harness matched or beat all of them on recall wherever they produced output. In certain cases, the other harnesses failed to scan one or more of the test applications due to language compatibility problems or excessively long scan execution time. The model + harness pairing appears to be critical. The other harnesses permit use of a local model, but seem to be optimized for the frontier. Metis is the clearest example. Paired with GPT-5.5 it did very well. On a local model it finished only one of the six targets, even after I patched v1.3.0 to raise its request timeouts to accommodate slower responses from the local model. On the one target it completed, it found less than my harness did.\n\nAnother challenge that I had with the open-source harnesses was the lack of phased execution and intermediate outputs. My harness aims to help pentesters, not be an autonomous click and forget solution. As a pentester, I want output quickly and often so that I can take action on interesting leads. When other harnesses ran for hours and saved all output until the end, it stung to learn that the results weren’t worth the wait. I also want to judge each phase. Are results of generation more reliable than refutation later? How do I tune it?\n\n**Confidently Wrong**\n\nThe challenge that has affected my AI work the most is only tangentially related to vulnerability scanning. A long Claude Code conversation presents as one continuous thread, but the context that actually reaches the model is summarized and pruned as it grows. When that pruning drops something important, the answers keep arriving with the same confident tone. Claude Code notifies the user when the context is compacted, but I struggle to ensure that the critical details are all brought back into context. I only realize I have a context problem when the model’s advice is obviously flawed. I assume subtler cases have escaped my attention and potentially hid some problems that I’ll discover later.\n\nConfidently wrong answers have more than one cause. In some scenarios, the model had the information in context and lost it to compaction. It was there before, so I don’t realize the latest responses are no longer based on the same context I expect. In other cases, the model never had the information and produced a guess. It doesn’t call it a guess at first though. Only when I push back will the model take an action to retrieve the necessary information instead. A third situation happens when the model has information that is simply out of date and is reasoning correctly about an earlier version of the code, the file, or the decision.\n\nA fourth case is the hardest one to catch. The model recalls something accurately but attaches it to the wrong thing. It will cite a result I really did measure, and the number will be correct, but it came from a different target, or a different run, or a different harness than the one we are discussing. Every piece of the claim holds up on its own. The fact is real, the source is real, and if I go looking for where the number came from, I find it. What is gone is the boundary that kept it separate from the thing we are talking about now.\n\nThe model will apologize when called out for these mistakes, but it will eventually forget the mistakes just like it forgot the other context. To ensure that the right information is used, explicit intervention is necessary: re-read the file, re-run the test, open a fresh session, ask a different model.\n\nThis is a challenge that all harnesses face. There are limits to the context that the models can receive, so harnesses must make determinations about what to truncate and what to save and transmit. My pentesting harness compacts context when a run gets long. My SAST harness never compacts, and it caught me a different way. Ollama’s default context window is 2048 tokens, far below what the model actually supports. At that setting the per-file pass silently truncated my two largest source files and returned nothing for them. Nothing errored. The harness recorded a clean scan of code the model had never seen.\n\n**Where This Leaves Me**\n\nA year ago, I didn’t think AI harnesses were worth the setup time for application security work. I don’t believe that anymore. Even as a new user, I was getting models to find and demonstrate vulnerabilities that traditional SAST applications could not. Still, they did not replace judgment. In my experience, the AI harnesses made me more efficient, but they didn’t fundamentally change my workflow. More vulnerabilities can be found cheaply, but for a web application penetration test, I still need to discard false positives in the output and I still need to hunt for the false negatives that the harnesses still couldn’t uncover. The signal-to-noise ratio is better now, and I expect it will continue to improve with both model improvements and improvements to the harnesses.\n\nThe pairing of penetration testers with AI systems is like the pairing of harnesses and models. The best results come from the combination, not from either side on its own. Modern models with good harnesses are powerful and belong in everyone’s toolset, but a tool without a tester is as incomplete as a model without a harness.\n\nThat applies to the people buying this work as much as to the people doing it. Both need to understand their needs in fine enough detail to ask for what they want. “Solve my problem and don’t hallucinate” does not work yet, any more than “find all the vulnerabilities” did when I started.", "url": "https://wpnews.pro/news/web-app-pentesting-in-the-ai-era", "canonical_source": "https://blog.includesecurity.com/2026/08/web-app-pentesting-in-the-ai-era/", "published_at": "2026-08-10 16:00:00+00:00", "updated_at": "2026-08-10 16:26:04.403068+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-tools", "ai-research"], "entities": ["IncludeSec", "LLM"], "alternates": {"html": "https://wpnews.pro/news/web-app-pentesting-in-the-ai-era", "markdown": "https://wpnews.pro/news/web-app-pentesting-in-the-ai-era.md", "text": "https://wpnews.pro/news/web-app-pentesting-in-the-ai-era.txt", "jsonld": "https://wpnews.pro/news/web-app-pentesting-in-the-ai-era.jsonld"}}