{"slug": "stop-letting-ai-write-security-bugs-introducing-hallint", "title": "Stop Letting AI Write Security Bugs: Introducing \"hallint\"", "summary": "A developer built hallint, a free open-source static analysis tool specifically tuned to catch security bugs generated by AI coding assistants like Copilot and ChatGPT. The tool scans JavaScript, TypeScript, and Python codebases for 11 targeted rules including hardcoded secrets, SQL injection, and missing authentication, addressing failure modes that traditional linters miss.", "body_md": "We are all using Copilot, Cursor, or ChatGPT to write code faster. They save time, tackle boilerplate, and help us think through complex logic. But there is a massive blind spot that the industry isn't talking about enough: **AI coding assistants generate the exact same class of security bugs, over and over again, with total confidence.**\n\nTraditional linters like ESLint are fantastic, but they were designed for human-written code. They catch unused variables and missing semicolons. They aren't built to catch the subtle, plausible-looking security holes that LLMs naturally default to.\n\nThat is why I built **hallint**. It is a free, open-source static analysis tool specifically tuned to catch the failure modes of AI code generation before they reach your production environment.\n\nAI assistants fail differently than humans do. When you ask an LLM to generate an Express route or a database query, it tends to take the path of least resistance. It writes code that passes casual review, runs perfectly in local development, and creates devastating vulnerabilities once deployed.\n\nHere are a few classic AI failure patterns:\n\n**Hardcoded Secrets:** AI will happily spit out `const API_KEY = \"sk-abc123...\"`\n\n. It passes linting, but pushing it to a public repo is a disaster.\n\n**SQL Injection by Default:** AI loves template literals. `db.query(\"SELECT * FROM users WHERE id = ${req.params.id}\")`\n\nlooks completely fine at a glance, but it is a textbook SQL injection vector.\n\n**Missing Authentication:** Generating CRUD routes is easy. Remembering to apply auth middleware to every single one of them? AI forgets constantly.\n\n**Auth Masking:** This is a particularly insidious AI habit. When asked to add error handling to auth middleware, an LLM will often generate a `try/catch`\n\nblock that catches a token error but still calls `next()`\n\n, silently allowing unauthenticated requests through.\n\n**Permissive CORS:** Setting `cors({ origin: '*' })`\n\nis the AI's favorite one-liner to \"fix\" your CORS errors.\n\n`hallint`\n\n?\n**hallint** is a TypeScript library and CLI tool that scans your JavaScript, TypeScript, and Python codebases for these specific AI-generated security and quality issues.\n\nInstead of trying to be a general-purpose linter, it uses three detection layers to target AI-specific code smells:\n\n`hallint`\n\ncurrently ships with **11 targeted rules**:\n\n| Rule | Severity | What it catches |\n|---|---|---|\n`hardcoded-secret` |\nCritical |\nAPI keys, tokens, and known prefixes (`ghp_` , `sk-` ). |\n`sql-injection` |\nCritical |\nUser input directly interpolated into SQL queries. |\n`unsafe-eval` |\nCritical |\n`eval()` or `new Function()` using dynamic input. |\n`auth-masking` |\nCritical |\nCatch blocks that swallow auth errors, making failures silently pass. |\n`missing-auth-check` |\nHigh |\nRoute handlers missing authentication middleware. |\n`xss-innerHTML` |\nHigh |\nUnsanitized strings assigned directly to `.innerHTML` . |\n`permissive-cors` |\nHigh |\n`cors({ origin: '*' })` left in route handlers. |\n`jwt-in-localstorage` |\nHigh |\nJWTs or auth tokens being stored in `localStorage` . |\n`swallowed-error` |\nHigh |\nEmpty or comment-only catch blocks. |\n`http-not-https` |\nMedium |\nHardcoded `http://` URLs in fetch/axios requests. |\n`async-no-catch` |\nMedium |\n`async` functions with no error handling at all. |\n\n`hallint`\n\nYou can use `hallint`\n\nas a quick CLI scanner or integrate it deeply into your Node.js tooling.\n\nYou don't even need to install it to try it out. Just point it at your source directory using `npx`\n\n:\n\n```\nnpx @asyncinnovator/hallint-cli ./src\n```\n\n**Example Output:**\n\n```\nhallint scanning ./src...\n\nsrc/routes/users.ts\n  users.ts:4  CRITICAL  [hardcoded-secret]\n  Hardcoded secret detected — API key, token, or password in source code\n  > const apiKey = \"sk-abc123def456ghi789jkl\"\n  fix: Move to environment variables: process.env.YOUR_SECRET_NAME\n\n  users.ts:9  CRITICAL  [sql-injection]\n  Possible SQL injection — user input directly concatenated into a query string\n  > const result = await db.query(`SELECT * FROM users WHERE name = ${req.query.name}`)\n  fix: Use parameterized queries: db.query('SELECT * FROM users WHERE name = $1', [req.query.name])\n\nSummary: 2 issue(s) in 1 file(s) — 12ms\n  2 critical\n```\n\nIf you are building your own testing pipelines, pre-commit hooks, or editor plugins, you can import the core library directly:\n\n```\nnpm install @asyncinnovator/hallint\njs\nimport { scan, scanSource } from '@asyncinnovator/hallint'\n\n// Scan your file system\nconst result = await scan({\n  files: ['./src/**/*.ts'],\n  rules: 'recommended',\n  minSeverity: 'high',\n})\n\n// Or scan raw strings directly without touching the filesystem\nconst findings = scanSource(\n  `const key = \"sk-abc123abc123abc123abc\"`,\n  'virtual.ts'\n)\n```\n\nIf you want to integrate the CLI directly into your CI/CD pipelines (like GitHub Actions) as a hard merge gate, configure ESLint-style inline rule suppressions, set up public route allowlists to reduce noise, or enable the optional LLM-powered plain-English explanations, you will find everything you need in our official documentation.\n\nWe want to keep this blog post focused on the core problem, so for advanced configurations, architecture details, and guides on how to write your own custom rules in under 30 lines of code, head over to our repository.\n\n👉 [Read the full documentation on GitHub](https://github.com/Asyncinnovator/hallint)\n\nAI is changing how we write code, but we need tools that adapt to the new mistakes we are making. `hallint`\n\nis MIT licensed, community-driven, and highly extensible. If you've seen an AI-specific vulnerability pattern that we don't catch yet, pull requests are always welcome!", "url": "https://wpnews.pro/news/stop-letting-ai-write-security-bugs-introducing-hallint", "canonical_source": "https://dev.to/asyncinnovator/stop-letting-ai-write-security-bugs-introducing-hallint-2hh2", "published_at": "2026-07-21 08:40:47+00:00", "updated_at": "2026-07-21 09:03:25.509959+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-safety", "developer-tools", "ai-products"], "entities": ["hallint", "Copilot", "Cursor", "ChatGPT", "ESLint", "TypeScript", "Python"], "alternates": {"html": "https://wpnews.pro/news/stop-letting-ai-write-security-bugs-introducing-hallint", "markdown": "https://wpnews.pro/news/stop-letting-ai-write-security-bugs-introducing-hallint.md", "text": "https://wpnews.pro/news/stop-letting-ai-write-security-bugs-introducing-hallint.txt", "jsonld": "https://wpnews.pro/news/stop-letting-ai-write-security-bugs-introducing-hallint.jsonld"}}