DEV Community

Sentrint
Sentrint

Posted on

The dangerous thing about AI-generated code is how normal it looks

A missing authentication check does not stop your application from compiling.

Neither does an exposed admin route, an overly permissive CORS policy, or a secret bundled into client-side JavaScript. The feature can work, the tests can pass, and the deployment can succeed while all of those problems remain in the code.

That is the security gap I keep running into with AI-assisted development.

Coding agents are good at producing working changes quickly. They are also good at producing enough code that reviewing every line becomes difficult. When an agent returns a 400-line diff, it is easy to focus on the feature you requested and skim over the configuration change or route handler that creates the actual risk.

The problem is not simply that AI writes insecure code. Humans write insecure code too. The difference is the volume and speed at which code can now be produced.

Working code and secure code are different tests

Most development feedback loops answer questions such as:

  • Does the project compile?
  • Do the tests pass?
  • Does the page render?
  • Does the requested feature work?
  • Did the deployment succeed?

Those are useful checks, but they do not tell you whether an endpoint has the right authorization, a webhook signature is verified, a database policy is enabled, or sensitive data has reached the browser.

Security mistakes are often quiet. They do not necessarily cause visible failures, which makes them particularly easy to miss in a large generated diff.

This changes how I think about reviewing agent-written code. Instead of treating security as part of a general skim, it needs its own pass.

A practical scan-and-rescan workflow

The workflow I now use is deliberately simple:

  1. Let the agent implement the feature.
  2. Run the normal tests and review the behavior.
  3. Scan the repository for security problems.
  4. Fix one class of issue at a time.
  5. Review and test each change.
  6. Push the changes and scan again.

The rescan matters. A plausible-looking fix is not the same as a verified fix, especially when another agent produced it.

I also avoid asking an agent to β€œfix all security issues” in one instruction. That tends to produce a large diff containing unrelated refactors, dependency changes, and speculative rewrites. Small, constrained requests are easier to review and less likely to break working behavior.
A useful repair instruction should identify the location, explain the security requirement, constrain the scope, and define what must remain unchanged. It should also distinguish between changes that can be made in code and actions that require a human.

A leaked credential is a good example. Removing it from the repository is only one step. The credential may also need to be revoked, rotated, removed from Git history, and replaced in the deployment environment. No code patch can complete all of that safely on its own.

Static rules are useful, but findings need context

Traditional security scanners can be noisy. A pattern may be dangerous in one location and harmless in another, so dumping a long list of warnings on a developer is rarely enough.

At the same time, asking a language model to invent the entire security review from scratch introduces a different problem: the result can change between runs, and the advice may be confident without being reproducible.

The approach I have found more useful is to separate the process into two parts:

  • Established rules identify potential problems.
  • Contextual review helps determine whether those findings are relevant.

The repair guidance should remain constrained and reproducible. If the same issue produces radically different advice each time it is scanned, it becomes difficult to test the workflow or trust the result.

Security tools should not create another review problem

There is an obvious temptation to let a scanner modify the repository automatically. I have avoided that in my own workflow.
If the original problem is that agents produce more code than I can carefully review, allowing a security tool to generate another large, automatic diff recreates the same problem under a more reassuring label.

I want the scanner to show me the evidence and propose a narrow repair. I still want to decide whether that repair belongs in the application.

That is the idea behind Sentrint, a tool I built for this workflow. It scans a GitHub repository and turns its findings into copy-paste repair prompts for coding tools. It does not modify the repository, open pull requests, or push changes.

The linked sample is a real, redacted report rather than a landing page:

https://sentrint.com/sample

I am not claiming that automated scanning replaces a penetration test, code review, or an understanding of the application's business logic. It cannot know every authorization rule your product is supposed to enforce. The goal is narrower: catch the security mistakes that can otherwise hide inside code that appears to work perfectly.

If you build with coding agents, I would be interested to know how you review their output. Do you read every line, rely on tests, run a scanner, or use a different process entirely?

Top comments (0)