Security Scanner — VS Code Extension
Scans your local git changes for security issues using Gitleaks + Semgrep + OpenAI, then uses AI to explain each issue, suggest a best-practice fix, and generate a ready-to-paste prompt for Cursor or GitHub Copilot.
Workflow
Local file changes
│
├── Gitleaks ← secrets, API keys, credentials (150+ rules)
├── Semgrep ← injection, XSS, auth, crypto, logging, config (3000+ rules)
└── OpenAI ← catches issues Gitleaks and Semgrep missed;
surfaces findings that are realistically exploitable
(exploitability score ≥ 7/10)
│
▼
Diagnostics ← red squiggles on affected lines + Problems panel entries
│
▼
OpenAI analysis ← for each issue: plain-English explanation, complete
best-practice fix, 3 remediation steps, and an
agent prompt to paste into Cursor / Copilot
│
▼
Alert popups ← one panel per issue category, severity-themed image
chosen at random from a pool; no auto-dismiss timer —
you choose Mark as fixed or Dismiss before the next appears
│
▼
Sidebar panel ← persistent record of every finding + fix;
browsable after the popups are gone
│
▼
All clear panel ← shown instead of alerts when the scan finds nothing
Both tools must be on your PATH.
Gitleaks (secret detection)
# macOS
brew install gitleaks
# Linux
curl -sSfL https://raw.githubusercontent.com/gitleaks/gitleaks/main/scripts/install.sh | sh -s -- -b /usr/local/bin
# Windows (winget)
winget install gitleaks
Semgrep (SAST — 3000+ rules)
# macOS
brew install semgrep
# macOS / Linux (pip)
pip3 install semgrep
# or, if pip3 isn't found:
python3 -m pip install semgrep
# Windows
pip install semgrep
Verify both work:
gitleaks version
semgrep --version
2. Install the extension
cd security-scanner
npm install
npm run compile
Press F5 (or Run → Start Debugging) in VS Code to launch the Extension Development Host for development testing.
To package for distribution:
npm install -g @vscode/vsce
vsce package
# install locally:
code --install-extension security-scanner-0.0.1.vsix
If npm install -g fails with EACCES, prefix with sudo.
If code isn't found, run Cmd+Shift+P → Shell Command: Install 'code' command in PATH inside VS Code first.
3. Set your OpenAI API key
The AI features require your own OpenAI API key. The extension never bundles or shares one — your key is sent only directly to OpenAI's API, and you are billed directly by OpenAI for your usage.
Get a key: https://platform.openai.com/api-keys
Option A — VS Code settings (recommended):
Cmd+Shift+P → Preferences: Open User Settings (JSON)
{
"securityScanner.openaiApiKey": "sk-...your-key-here"
}
Option B — environment variable:
export OPENAI_API_KEY="sk-...your-key-here"
Quit VS Code fully and relaunch from the same terminal for the variable to be picked up.
If no key is configured, Gitleaks + Semgrep still run and show squiggles and Problems panel entries — only the AI explanation, fix code, agent prompt, and AI-only findings are skipped. A one-time warning notification will point you to the setting.
| Setting |
Default |
Description |
securityScanner.openaiApiKey |
"" |
Your OpenAI API key |
securityScanner.autoScanOnCommit |
true |
Auto-scan when changes are detected |
securityScanner.semgrepRuleset |
p/owasp-top-ten |
Primary Semgrep ruleset |
securityScanner.aiScanEnabled |
true |
Enable/disable the OpenAI supplementary scan |
Other useful Semgrep rulesets you can set as the primary ruleset:
p/javascript — JS/TS specific rules
p/python — Python security rules
p/security-audit — Broad security audit
p/owasp-top-ten — OWASP Top 10 (default)
The extension also runs p/sql-injection, p/nodejs, p/xss, p/command-injection, and p/insecure-transport automatically alongside the primary ruleset.
5. Usage
Manual scan:
Cmd+Shift+P → Security Scanner: Scan Changes
- Or click Scan staged changes in the Security Fixes tab in the Explorer sidebar
Auto scan:
The extension watches .git/index and auto-scans 800ms after changes are detected.
Reading results:
- Gitleaks, Semgrep, and the OpenAI supplementary scan all run. Red squiggles appear on affected lines and the Problems panel lists every finding.
- OpenAI generates for each issue:
- A plain-English explanation of the exact attack path
- A complete, drop-in best-practice fix (not a minimal one-line patch)
- 3 remediation steps covering the immediate change, surrounding dependencies, and verification
- A ready-to-paste agent prompt for Cursor or GitHub Copilot Chat
- One alert panel appears per issue category. Each panel shows:
- A severity-themed image picked at random from a pool
- The affected file(s), each clickable to jump directly to the flagged line
- The AI explanation, fix steps, and suggested code with a Copy fix button
- Mark as fixed — suppresses this AI issue and advances to the next alert
- Dismiss — skips without suppressing, and advances to the next alert
- The Security Fixes sidebar panel in Explorer shows every finding with its AI fix, persistently browsable after the popups close.
- If the scan finds zero issues, an All clear panel appears confirming it is safe to commit.
6. Suppressed issues
When you click Mark as fixed on an alert, the AI issue is fingerprinted by its file path, category, and the actual source code at the flagged line. It will not reappear on future scans as long as that line of code remains unchanged. If you edit the flagged line, the suppression expires and the issue re-surfaces for review.
To view and manage suppressed issues:
Cmd+Shift+P → Security Scanner: View Suppressed Issues
This opens a panel listing every suppressed AI finding with its file, category, and code snippet. Each row has an Unsuppress button to restore a single finding, and a Clear all suppressions button to wipe everything at once.
Note: only AI findings are suppressed this way. To suppress a Semgrep false positive, add a // nosemgrep comment on the flagged line instead (see below).
7. Suppressing Semgrep false positives
If Semgrep flags a line that is already correctly secured (e.g. a parameterised query that gets flagged because the rule matches the call pattern without tracing the values array), add a // nosemgrep comment on that line:
const query = 'SELECT * FROM users WHERE id = ?'; // nosemgrep
db.query(query, [req.params.id], callback);
This is the standard Semgrep mechanism for per-line suppression and persists across scans because it lives in the source code itself.
What gets caught
Via Gitleaks
- AWS / GCP / Azure credentials
- GitHub / GitLab / Bitbucket tokens
- Stripe, Twilio, Slack, SendGrid, Mailgun keys
- Private keys (RSA, EC, DSA, PGP)
- Database connection strings with passwords
- JWT secrets and OAuth client secrets
- Generic high-entropy strings in variables named key, secret, token, password
Via Semgrep (9 rulesets, 3000+ rules)
- SQL injection via string concatenation or template literals
- NoSQL / MongoDB query injection
- XSS via
innerHTML, outerHTML, document.write, dangerouslySetInnerHTML, v-html
- Command injection via
eval(), exec(), spawn(), Function() constructor
- Insecure cryptography (MD5, SHA1, DES, RC4, weak RSA key sizes)
- Hardcoded passwords in source code
- Sensitive data in logs (
console.log with password, token, SSN, credit card)
- Missing input validation (
req.body/req.query/req.params at dangerous sinks)
- Insecure CORS, missing cookie flags (
httpOnly, secure, sameSite)
- Path traversal, XXE, insecure deserialization, SSRF, open redirects, prototype pollution
Via OpenAI (supplementary scan)
Catches issues Semgrep and Gitleaks structurally cannot, including:
- Logic-level authorization mistakes (missing ownership checks, broken access control)
- Insecure direct object references
- Business logic vulnerabilities
- Missing rate limiting on sensitive endpoints
- Subtle authentication flow mistakes
The AI scan applies an exploitability filter — only findings scored 7 or above on a realistic 1–10 exploitability scale are surfaced. Theoretical or hard-to-trigger issues are dropped. The same root cause appearing multiple times in one file is deduplicated to a single finding.
Custom rules
The extension ships a src/scanner/custom-rules.yaml file covering gaps in public Semgrep rulesets:
- Sensitive data in
console.log (password, token, secret, apiKey, SSN, credit card)
- Sensitive data in template literal logs
- Unvalidated request input flowing into database, eval, file, or HTML sinks
To add your own rules, edit src/scanner/custom-rules.yaml following Semgrep rule syntax. After editing, recompile:
npm run compile
The compile step copies the YAML into out/scanner/ so it is available at runtime.
Troubleshooting
| Symptom |
Likely cause |
Fix |
| "Not inside a git repository" |
A parent folder is open, not the repo root |
File → Open Folder → select the folder that contains .git |
| "No changes to scan" |
No local file changes detected |
Make a change to a tracked file, then scan |
| AI fix never appears |
API key not set, or missing from settings |
Check securityScanner.openaiApiKey in settings |
| Same AI issue keeps reappearing after Mark as fixed |
Fingerprint mismatch — AI reproduced different matched text between scans |
Ensure you're on the latest version which fingerprints by actual source line |
| Semgrep flags a correctly secured line |
False positive on call-site pattern |
Add // nosemgrep on the flagged line |
SyntaxError: Bad escaped character in JSON |
Rare OpenAI formatting issue |
Extension retries automatically; check the Security Scanner — AI Debug output channel if it persists |
| Command not in Command Palette |
Extension needs recompile or reload |
npm run compile then Cmd+Shift+P → Developer: Reload Window |
EACCES during npm install -g |
No write permission to global npm directory |
Re-run with sudo |
code command not found in terminal |
VS Code CLI not on PATH |
Cmd+Shift+P → Shell Command: Install 'code' command in PATH |