LLM-Assisted Fuzzing: A New Approach to False-Positives

Preface: this post was ac­tu­ally writ­ten on February 24th, de­spite be­ing pub­lished to­day.

I’d like to do some re­flec­tion on how we can im­prove Harper’s out­put. It is fun­da­men­tally a process prob­lem. For con­text, let us go through a con­trived ex­am­ple.

Sumner Evans reported a bug to me while writing a tech talk about CI and CD
  1. Somebody (usually me) dis­cov­ers an er­ror in their writ­ing that Harper did not catch. This is a con­crete string like I have a a care in the world”.
  2. I look for other forms of the er­ror to see if I can gen­er­al­ize it to more cases. Here, we see an in­def­i­nite ar­ti­cle re­peat­ing it­self. We could just look for the ex­act string a a” and call it day, but we can cover more cases by look­ing for . In fact, we can gen­er­al­ize it even fur­ther. In this case, writ­ers want to avoid rep­e­ti­tions of any word that is not a ho­mo­graph.
  3. Once the code is writ­ten that de­fines the rule, I push it out, and wait to hear from users if any false-pos­i­tives arise.

This is a flawed sys­tem, par­tic­u­larly that last step. I’ve found some­thing a bit bet­ter.

I’ve been ex­per­i­ment­ing more with LLM tool­ing, par­tic­u­larly Ollama. With it, I’ve set up a use­ful sys­tem for iden­ti­fy­ing false-pos­i­tives be­fore push­ing changes out to users. I like to call it LLM Assisted Fuzzing”.

LLM-Assisted Fuzzing

Fuzzing is a com­mon prac­tice wherein en­gi­neers rapidly and con­tin­u­ously push ran­dom data through their sys­tem to de­ter­min­is­ti­cally check if it is be­hav­ing cor­rectly (i.e. not crash­ing). If a par­tic­u­lar batch of ran­dom data causes an is­sue, it is el­e­vated to an en­gi­neer.

Harper as a pro­gram stands in a some­what unique po­si­tion: it an­a­lyzes nat­ural lan­guage to iden­tify gram­mat­i­cal er­rors. LLMs ex­ist as a di­rect com­ple­ment to it: they gen­er­ate natural” lan­guage. Do you see where I am go­ing with this?

Let’s be clear: lan­guage mod­els do not gen­er­ate gram­mat­i­cally cor­rect text even a good amount of the time. As a re­sult, their out­put is use­ful as a proxy for our user’s writ­ten work. If we can im­ple­ment a fea­ture that re­li­ably cor­rects (without false-pos­i­tives) an LLMs out­put, we can rea­son­ably ex­pect it to work for our user’s text.

My Initial Attempt at LLM-Assisted Fuzzing

I started work­ing on this Friday morn­ing, and fi­nally have what I would call a first draft” of an LLM-assisted fuzzing sys­tem for iden­ti­fy­ing false-pos­i­tives. Here’s how it works:

I start a lo­cal Ollama server, pre­loaded with sev­eral mod­els (which I’ll ex­pand on more be­low).

I run a bash script that re­peat­edly feeds the same prompt into the mod­els us­ing a com­mand-line client for Ollama. This gives me a large dataset of re­sponses to the prompt. I’m not look­ing for the se­man­tic con­tent of the re­sponse. I’m in­ter­ested in ex­ten­sive cov­er­age of whichever lin­guis­tic do­main I’ve de­fined in the prompt. I can run this as long as I like be­fore go­ing on to the next step.

Once I have a large dataset, I run a sep­a­rate script that runs Harper over each re­sponse. If it finds an er­ror, the script opens the re­sponse in the Harper ed­i­tor for fur­ther in­spec­tion.

The biggest is­sue with this work­flow right now: re­gard­less of my prompts, the LLMs con­tinue to emit ac­tual gram­mat­i­cal er­rors. This means that when I go through this process, I get at least as many true-pos­i­tives as false-pos­i­tives. It also does noth­ing for false-neg­a­tives.

Tweaks

There are a cou­ple pa­ra­me­ters here that I’m go­ing to con­tinue to tweak as the work­flow be­comes more ma­ture. So far, I’ve been us­ing deepseek-r1:32b and mistral-small. DeepSeek tends to use more col­or­ful lan­guage than Mistral, which runs much faster on my ma­chine.

I’ve also been it­er­at­ing on the prompt as I go. Here’s the lat­est ver­sion:

Please write a long, drawn-out essay on a topic of your choosing.
Write out the essay multiple times before giving me your final draft.
Your final draft should be grammatically perfect, clearly demonstrating that you put time and effort into your submission.

I repeat: I do not want to see anything other than your final drafts.
Do not give me any intermediate work.

Furthermore, do not use any characters or words other than English. 
I do not want Chinese or anything else.

I have all the time in the world. I'm perfectly fine with waiting a little longer if it means you give me something you are proud of.

When I move on to tack­ling false-neg­a­tives with this, I’ll be able to prompt the model to give me spe­cific kinds of er­rors, which makes it sig­nif­i­cantly more use­ful than try­ing to track down ex­ist­ing work.