Stop Letting AI Write Security Bugs: Introducing "hallint" 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. 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. Traditional 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. That 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. AI 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. Here are a few classic AI failure patterns: Hardcoded Secrets: AI will happily spit out const API KEY = "sk-abc123..." . It passes linting, but pushing it to a public repo is a disaster. SQL Injection by Default: AI loves template literals. db.query "SELECT FROM users WHERE id = ${req.params.id}" looks completely fine at a glance, but it is a textbook SQL injection vector. Missing Authentication: Generating CRUD routes is easy. Remembering to apply auth middleware to every single one of them? AI forgets constantly. 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 block that catches a token error but still calls next , silently allowing unauthenticated requests through. Permissive CORS: Setting cors { origin: ' ' } is the AI's favorite one-liner to "fix" your CORS errors. hallint ? 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. Instead of trying to be a general-purpose linter, it uses three detection layers to target AI-specific code smells: hallint currently ships with 11 targeted rules : | Rule | Severity | What it catches | |---|---|---| hardcoded-secret | Critical | API keys, tokens, and known prefixes ghp , sk- . | sql-injection | Critical | User input directly interpolated into SQL queries. | unsafe-eval | Critical | eval or new Function using dynamic input. | auth-masking | Critical | Catch blocks that swallow auth errors, making failures silently pass. | missing-auth-check | High | Route handlers missing authentication middleware. | xss-innerHTML | High | Unsanitized strings assigned directly to .innerHTML . | permissive-cors | High | cors { origin: ' ' } left in route handlers. | jwt-in-localstorage | High | JWTs or auth tokens being stored in localStorage . | swallowed-error | High | Empty or comment-only catch blocks. | http-not-https | Medium | Hardcoded http:// URLs in fetch/axios requests. | async-no-catch | Medium | async functions with no error handling at all. | hallint You can use hallint as a quick CLI scanner or integrate it deeply into your Node.js tooling. You don't even need to install it to try it out. Just point it at your source directory using npx : npx @asyncinnovator/hallint-cli ./src Example Output: hallint scanning ./src... src/routes/users.ts users.ts:4 CRITICAL hardcoded-secret Hardcoded secret detected — API key, token, or password in source code const apiKey = "sk-abc123def456ghi789jkl" fix: Move to environment variables: process.env.YOUR SECRET NAME users.ts:9 CRITICAL sql-injection Possible SQL injection — user input directly concatenated into a query string const result = await db.query SELECT FROM users WHERE name = ${req.query.name} fix: Use parameterized queries: db.query 'SELECT FROM users WHERE name = $1', req.query.name Summary: 2 issue s in 1 file s — 12ms 2 critical If you are building your own testing pipelines, pre-commit hooks, or editor plugins, you can import the core library directly: npm install @asyncinnovator/hallint js import { scan, scanSource } from '@asyncinnovator/hallint' // Scan your file system const result = await scan { files: './src/ / .ts' , rules: 'recommended', minSeverity: 'high', } // Or scan raw strings directly without touching the filesystem const findings = scanSource const key = "sk-abc123abc123abc123abc" , 'virtual.ts' If 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. We 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. 👉 Read the full documentation on GitHub https://github.com/Asyncinnovator/hallint AI is changing how we write code, but we need tools that adapt to the new mistakes we are making. hallint is 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