Dev Encyclopedia
ArticlesToolsContactAbout

Get notified when new content drops

No spam. Just new articles, tools, and updates straight to your inbox.

Dev Encyclopedia

A reference for builders

Dev.to
Discord
WhatsApp Channel
daily.dev
Hashnode
X

Content

  • Articles
  • Tools
  • About
  • Contact

Connect

  • support@devencyclopedia.com
  • RSS Feed

Legal

  • Privacy Policy
  • Terms of Service
  • Disclaimer

© 2026 Dev Encyclopedia

Back to top ↑
  1. Home
  2. /
  3. Tools
  4. /
  5. DiffGuard
Free · Private · No uploads

Give that AI-generated diff one more look.

Paste a git diff and get an instant scan for the patterns agents quietly introduce when they optimize for “tests pass”: hardcoded secrets, disabled TLS checks, eval/exec injection, and SQL built by string concatenation. Nothing leaves your browser.

Zeeshan Tofiq

Zeeshan Tofiq

Full Stack Developer

How DiffGuard works

  1. 1

    Paste a git diff or patch

    Drop in the output of git diff, git diff --staged, a GitHub "Files changed" view, or a .patch file. Scanning runs as you type. If you paste plain code with no +/- markers, every line is treated as added.

  2. 2

    DiffGuard parses the added lines

    It walks the diff hunk by hunk, tracking file paths and new-file line numbers, and isolates the lines that were added. Removed and context lines are ignored for pattern checks, so you only see risks in the code the change introduces.

  3. 3

    Each added line runs through the rule set

    Regex and heuristic rules check for hardcoded secrets, disabled TLS/cert verification, eval/exec injection, SQL string concatenation, and suppressed warnings. The language toggle narrows the rules to JS/TS, Python, or Go to reduce false positives.

  4. 4

    Deletion balance is checked per file

    Separately, DiffGuard compares added versus removed line counts per file. A file that removes far more than it adds is flagged, because that is a common sign of an agent quietly dropping validation, error handling, or tests.

  5. 5

    Findings are ranked and explained

    Every finding shows a severity (High, Medium, Info), the exact file and line, the flagged code, and a one-line reason it matters. A summary badge at the top gives a fast go/no-go read: "2 High, 1 Medium" or "Clean."

  6. 6

    Copy the report or fix and re-scan

    Copy a plain-text report to paste into a PR comment, or fix the flagged lines and paste the new diff to confirm it comes back clean. Nothing is uploaded at any point.

What each finding means

Every finding carries a severity so you can triage fast. High findings are things that should almost never ship. Medium and Info findings are prompts to look closer, not automatic failures.

Hardcoded secrets: High

API keys, tokens, passwords, JWTs, and private-key blocks assigned to string literals. Agents add these to make a call succeed without wiring up real config. DiffGuard skips obvious placeholders and env-var references to keep the noise down.

+ const apiKey = "sk_live_5f3b9c2a71d84e6fa0c1b8e7d2394655";
+ AWS_ACCESS_KEY_ID = "AKIAIOSFODNN7EXAMPLE"
+ password: "hunter2correcthorse"
Disabled TLS verification: High

Turning off certificate validation to get past a self-signed-cert or handshake error. It makes the connection accept any certificate, which reopens man-in-the-middle attacks. This is the single most common "make the error go away" agent move.

+ new https.Agent({ rejectUnauthorized: false })   // JS
+ requests.get(url, verify=False)                   # Python
+ &tls.Config{ InsecureSkipVerify: true }           // Go
Code injection (eval / exec): High

eval(), new Function(), exec/system calls, and subprocess with shell=True. When any part of the executed string comes from input, this is a direct remote-code or command-injection risk.

+ eval(userInput)                                    // JS
+ os.system("ping " + host)                          # Python
+ subprocess.run(cmd, shell=True)                    # Python
SQL string concatenation: High

A SQL statement (SELECT / INSERT / UPDATE / DELETE) built by concatenating or interpolating a variable instead of using a parameterized query. The classic SQL injection pattern, and easy for an agent to write because it "works" in a demo.

+ db.query("SELECT * FROM users WHERE id = " + id)
+ cur.execute(f"DELETE FROM t WHERE name = '{name}'")
+ `UPDATE accounts SET bal = ${amount}`
Large net deletion: Medium

A file that removes far more lines than it adds. Often a legitimate refactor, but also the quietest way an agent makes failing tests pass: by deleting the validation, error handling, or test that was failing. Worth a second look, not an alarm.

# scripts/deploy.py
#   22 lines removed / 3 lines added
# → confirm the removed error handling was intentional
Suppressed warnings: Info

eslint-disable, @ts-ignore, # noqa, # nosec, and similar comments that silence a warning instead of fixing it. Not automatically wrong, but a signal the agent chose to hide an issue to reach green. Confirm the underlying code is actually safe.

+ // eslint-disable-next-line no-eval
+ result = eval(expr)  # nosec
+ const x: any = data // @ts-ignore

Patterns DiffGuard checks for

The exact signatures each rule set looks for on added lines. Language-specific rules only run when that language (or Auto) is selected.

Detected signatures
# Secrets (all languages)
AKIA[0-9A-Z]{16}            AWS access key ID
AIza[0-9A-Za-z_-]{35}       Google API key
ghp_… / github_pat_…        GitHub token
xox[baprs]-…                Slack token
eyJ….….…                   JWT literal
-----BEGIN PRIVATE KEY----- PEM private key
apiKey / secret / password = "literal"

# Disabled TLS (per language)
rejectUnauthorized: false             JS/TS
NODE_TLS_REJECT_UNAUTHORIZED = 0      JS/TS
verify=False / _create_unverified…    Python
InsecureSkipVerify: true              Go
CURLOPT_SSL_VERIFYPEER, false         any

# Injection (per language)
eval( … ) / new Function( … )         JS/TS
exec(…${var}) / exec("…" + var)       JS/TS
eval / exec / os.system( … )          Python
subprocess…(shell=True)               Python
exec.Command("sh", "-c", …)           Go

# SQL string building (all languages)
SELECT/INSERT/UPDATE/DELETE + "${var}" | "+" | f"…" | .format()

# Suppressed warnings (all languages)
eslint-disable · @ts-ignore · # noqa · # nosec · nolint

# Structural (all languages)
per-file: removed » added   →   large net deletion

These are heuristics. They favour catching the common case over perfect precision, so expect the occasional false positive (and use the language toggle to reduce them).

When to use DiffGuard

SituationWhat to paste
Before committing an agent's changegit diff (or git diff --staged)
Reviewing a Claude Code / Cursor sessiongit diff main...HEAD
Sanity-checking a contributor's PRThe GitHub "Files changed" diff
Auditing a patch file before applyingThe .patch / .diff file contents
Quick check on a snippet an agent gave youThe raw code (no markers needed)

Frequently Asked Questions

What does DiffGuard do?

DiffGuard scans a git diff or patch for the risky patterns that most often slip through when an AI coding agent writes the change: hardcoded secrets and API keys, disabled TLS/certificate verification, eval/exec-style code injection, SQL built by string concatenation, suppressed linter or security warnings, and disproportionately large deletions.

It reads only the added lines (the code the diff introduces), reports each finding with a severity, the exact file and line, and a one-line explanation of why it matters. It runs entirely in your browser as a fast pre-merge habit-check.

Does this replace a real security review?

No, and it is not trying to. DiffGuard is a thirty-second sanity pass on a single diff, built for the individual developer or small team without org-wide security tooling. It uses regex and simple heuristics, so it will have both false positives and false negatives.

For a company setting you still want real tooling. DiffGuard is honest about where it sits:

DiffGuardGitGuardian / Semgrep / GitHub Advanced Security
SetupPaste a diff, no accountGitHub App install, account, config
Where it runs100% in your browserCI pipeline / cloud service
CostFree forever, no tokenPaid for teams / orgs
ScopeOne diff, common patternsWhole repo, deep analysis, history
Best forThe quick personal checkThe org-wide security gate
What languages does it support?

DiffGuard has tuned rule sets for JavaScript/TypeScript, Python, and Go, plus language-agnostic checks (secrets, SQL concatenation, large deletions) that run for everything. Use the language toggle above the paste box to narrow the rules to one language and cut down false positives from generic regex matching.

In Auto mode every rule runs, which is the best choice when a diff touches more than one language.

Is my diff private? Does anything get uploaded?

Nothing is uploaded. There is no server round-trip, no LLM call, and no API key of any kind. All pattern matching happens in JavaScript inside your tab, so the diff never leaves your machine.

💡 Tip

Because there is no backend, it is safe to paste a diff that contains real (if temporary) secrets, and the page keeps working offline once loaded.

How do I get a diff to paste in?

For unstaged changes, run git diff. For work you have already staged, run git diff --staged. To review what an agent just did on a branch, diff against your base branch:

bash
# everything not yet committed
git diff

# only staged changes
git diff --staged

# an agent's branch vs main
git diff main...HEAD

You can also paste a diff straight from GitHub's "Files changed" view or a .patch file. If you paste plain code with no +/- markers, DiffGuard treats every line as added and scans it anyway.

Why does it flag large deletions? Deleting code is normal.

It is an intentionally noisy, low-severity heuristic. When an agent is optimizing for "tests pass," one of the quietest ways it gets there is by removing the code that was failing: a validation check, an error branch, a rate limit, or a test.

DiffGuard flags a file only when the removals are much larger than the additions (at least 12 lines removed and more than double the lines added). It is a Medium finding that says "confirm this was intentional," not an error. A legitimate refactor or file move will trip it, and that is fine.

If DiffGuard says "clean," is the diff safe?

No. "Clean" means none of DiffGuard's pattern checks matched the added lines, not that the change is correct or secure. A logic bug, a subtle auth bypass, or a secret in an unusual format can all pass a heuristic scan.

Treat a clean result as "nothing obvious jumped out" and still read the diff. DiffGuard is there to catch the easy-to-miss patterns in a tired end-of-day skim, not to sign off on the change.

Related reading

Security

npm postinstall Attacks in 2026

How malicious lifecycle scripts sneak code into your machine, and why a second pass on what a change actually introduces matters.

Security

GitHub Actions Security

Hardening CI so the risky patterns DiffGuard flags locally do not make it to production through your pipeline.

Zeeshan Tofiq

Zeeshan Tofiq

Full Stack Developer

Full stack developer with over 6 years of experience building production applications. Writes practical guides on JavaScript, TypeScript, React, Node.js, and cloud infrastructure. Focused on helping developers solve real problems with clean, maintainable code.

Enjoyed this article?

Get practical dev guides, tool updates, and new articles delivered straight to your inbox. No spam, unsubscribe anytime.