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.
How DiffGuard works
- 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
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
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
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
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
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.
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"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 } // Goeval(), 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) # PythonA 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}`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 intentionaleslint-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-ignorePatterns 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.
# 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 deletionThese 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
| Situation |
|---|
| Before committing an agent's change |
| Reviewing a Claude Code / Cursor session |
| Sanity-checking a contributor's PR |
| Auditing a patch file before applying |
| Quick check on a snippet an agent gave you |
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:
| DiffGuard | GitGuardian / Semgrep / GitHub Advanced Security | |
|---|---|---|
| Setup | Paste a diff, no account | GitHub App install, account, config |
| Where it runs | 100% in your browser | CI pipeline / cloud service |
| Cost | Free forever, no token | Paid for teams / orgs |
| Scope | One diff, common patterns | Whole repo, deep analysis, history |
| Best for | The quick personal check | The 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.
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:
# everything not yet committed
git diff
# only staged changes
git diff --staged
# an agent's branch vs main
git diff main...HEADYou 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.