Five Vulnerabilities Slipped Past Human Engineers. We Asked Qoder to Rewrite the Code

Summary: Five real-world vulnerabilities. Five legitimate feature requests. We gave those requests to Qoder Agent without a word about security, then ran /security-scan on the finished code to see what it would catch.

Imagine you are building a content website and receive this feature request: a user pastes an image URL, and the server automatically downloads the image and saves it as a cover.

Is there anything wrong with that request?

Not at first glance. Countless products offer the same feature, sparing users the trouble of downloading an image and uploading it again. That is exactly what the open-source comic server Kavita did: the feature was implemented, passed code review, and was merged and released.

Later, that code acquired another name: CVE-2022-2756. A CVE identifier is a globally recognized reference for a publicly documented security vulnerability. Once assigned, it gives the vulnerability a formal record that anyone can look up. The problem here was simple: the server fetched a URL on the user’s behalf without checking where it pointed. The destination could be an image—or the server itself, an internal network address, or anything else an outsider should not be able to reach.

There are plenty of requests like this. We picked five.

An Experiment

Five feature requests, drawn from five real open-source projects, corresponding to five publicly disclosed historical CVEs that have already been fixed. They shared one thing: when the vulnerabilities were introduced, nobody set out to write “dangerous code.” Developers were implementing legitimate requirements. Their code passed review. The problems surfaced much later.

We ran an experiment. We reconstructed the five feature requests as five prompts and asked Qoder Agent to implement them in specified historical versions of the corresponding projects. The prompts described only how to implement the features, without mentioning security at all. Once the code was written, we ran /security-scan to see whether it could catch, right there in the coding session, what human engineers had missed back then.

The checks were performed by Qoder Security, Qoder’s newly launched code security capability, built directly into Qoder Agent sessions. It can identify security issues as soon as the agent finishes writing code; /security-scan is the command for manually initiating a scan. Let’s see what Qoder Security actually finds.

We selected these five scenarios:

  1. Support a new data format (OpenSearch Ruby, CVE-2022-31115)
  2. Import a cover image from a URL (Kavita, CVE-2022-2756)
  3. Upload a file and restore a data backup (Qdrant, CVE-2024-2221)
  4. Add convenience methods for database operations (Flight PHP, CVE-2026-42550)
  5. Add custom arguments to an audio-processing command (discordrb, CVE-2023-28102)

Data parsing, network access, the file system, databases, and system commands: five of the most common security boundaries.

To keep this article focused, we will look at two in detail.

The Journey of a Filename

Of the five scenarios, Qdrant had the longest data-flow path leading to a vulnerability. It is a vector database that many AI applications now use to store and retrieve data.

Our request to Qoder Agent was to add a snapshot upload endpoint. Think of a snapshot as a complete backup of the database at a particular point in time. The endpoint should accept an uploaded snapshot file, save it to a designated directory, and then use the existing workflow to restore the data. The request included one entirely natural instruction: if the upload includes a filename, use that filename when saving the file.

The agent implemented the feature. Its changes focused on the upload endpoint and followed the project’s existing coding style. Then we ran /security-scan.

The scan report pointed straight to that “entirely natural” filename. It traced the complete data flow: the filename entered through the upload request, was used to construct the destination path, and eventually reached a file-write operation, passing through several layers of functions and modules along the way. If the filename contained a directory traversal sequence such as ../, the file would be written outside the snapshot directory. Where would it end up? Wherever the person crafting the filename wanted it to go.

Inspect any one function along that path in isolation, and nothing looks wrong. One function accepts the input; another constructs the path. Each appears to do its job. The risk becomes visible only when the entire chain is connected—which is exactly what file-by-file review struggles to reveal.

The report also proposed a fix: normalize and validate the filename, then verify that the final normalized path remains inside the snapshot directory. We asked the agent to apply the fix in the same session. The project’s tests still passed. We scanned again, and the same type of risk was no longer reported along that path.

The Power of a String

The second scenario was much quicker.

discordrb is a Discord bot framework widely used in the Ruby community. For voice processing, it invokes FFmpeg, a common command-line tool for working with audio and video. The request was to let callers pass an options string containing additional FFmpeg arguments, making it easier to add capabilities such as trimming and filters.

One optional parameter. A few lines of code. The scan found that the string was interpolated into a command passed to the system shell. Ordinary arguments caused no trouble. But a semicolon or a pair of backticks could inject another command and make the machine do something entirely unrelated. The only thing separating “support additional arguments” from “let the caller rewrite the entire shell command” was the caller’s goodwill.

The fix was to pass the arguments differently: supply them as individual elements of an argument list, rather than assembling a single string for the shell to interpret. A small change preserved the functionality while enforcing the security boundary.

The Other Three Scenarios

The remaining three followed the same process. Here are the key findings.

Format compatibility (OpenSearch Ruby). The request was to let the client accept service responses in YAML format. The scan identified the problem: data returned by the server was passed to an overly permissive parsing API. Such an API can do more than read data—it can instantiate objects and trigger behavior within the program. Supporting another format is not inherently wrong. The danger is that the input comes from outside the application, and someone else controls its contents.

Importing a cover image from a URL (Kavita). This was the request described at the beginning. The scan followed the path from “the endpoint receives a URL” to “the server downloads its contents” and identified missing restrictions on the destination: addresses pointing to the server itself or to internal networks were not blocked.

Database convenience methods (Flight PHP). The request was to wrap several common database write operations in helper methods to reduce repetitive code. The generated implementation used parameter binding for every query value—the standard defense against SQL injection, ensuring that data remains data and cannot alter the query itself. Textbook practice. The scan flagged a different layer: table and column names were concatenated directly into the SQL statement, and neither can be protected through parameter binding. The values were protected. What about the table names?

All Five Vulnerabilities Were Originally Written by Humans

In hindsight, none of these five vulnerabilities began with someone deciding to write dangerous code. Each started with a perfectly reasonable requirement: support another format, save users a step, or eliminate a few lines of repetitive code. Experienced engineers wrote the implementations. The code was reviewed. Yet the vulnerabilities still made it through.

If you run a one-person company (OPC) and rely on AI to turn ideas directly into products, this matters even more. The engineers who wrote those five vulnerabilities at least had colleagues reviewing their work. When it is just you and an agent, there is often no second pair of eyes.

So the point of this experiment is not that “AI-generated code is insecure.” These risks exist when humans write the code, and they remain when agents write it. AI-assisted coding also produces code at a much greater volume. What needs to change is when security feedback arrives.

If the report arrives only after the code has been committed, before release, the developer has already moved on. They must reconstruct the context from days earlier while sifting through a flood of alerts to separate genuine issues from false positives. Feedback delivered during the coding session is different: as soon as the code is written, discovery, understanding, remediation, and verification can all happen in one continuous flow, within the same session. That is why Qoder Security is built into agentic coding.

Try the Experiment Yourself

There is no secret recipe behind these five experiments. The projects are open source on GitHub, the versions are specified, and the prompts are provided in full. We have compiled a complete walkthrough covering environment setup, the original prompts, how to trigger each scenario, and what to look for. Following the guide takes about half an hour per scenario.

Full reproduction guide: Qoder Security in Practice | Qoder

Qoder Security is available first in Qoder Desktop and Qoder CLI. Enable it with one click in Settings to proactively scan for potential security risks. You can also enter/security-scanat any time to initiate a scan manually.

To try it yourself, choose the scenario closest to your everyday development work and follow the guide.

Or take an even simpler approach: while building a new feature in Qoder Desktop or Qoder CLI, run a scan and see what it catches.

(The scenarios in this article are based on publicly disclosed historical security issues that have already been fixed. They are intended solely to examine the detection of similar risks during coding; they do not imply that Qoder reproduced or rediscovered the corresponding CVEs. References to open-source projects and CVEs identify the sources of the scenarios only and do not imply any partnership or endorsement. Run these experiments locally or in an authorized, isolated environment. Scan results may vary depending on the product version, project state, and session context.)