██╗ ██╗ █████╗ ██╗ ██╗ ██╗███╗ ██╗████████╗
██║ ██║██╔══██╗██║ ██║ ██║████╗ ██║╚══██╔══╝
███████║███████║██║ ██║ ██║██╔██╗ ██║ ██║
██╔══██║██╔══██║██║ ██║ ██║██║╚██╗██║ ██║
██║ ██║██║ ██║███████╗███████╗██║██║ ╚████║ ██║
╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═╝
Static analysis for AI-generated code. Catch the security holes Artificial Intelligence leave behind — before they reach production.
AI coding assistants (Copilot, Cursor, etc.) are fast, but they consistently introduce the same classes of bugs: hardcoded secrets, SQL injection, missing auth, unsafe eval. hallint catches them.
npm install @asyncinnovator/hallint
Or run without installing:
npx @asyncinnovator/hallint-cli ./src
Requirements: Node.js >= 18
npx @asyncinnovator/hallint-cli ./src
npx @asyncinnovator/hallint-cli "./src/**/*.ts"
npx @asyncinnovator/hallint-cli ./src --min-severity high
npx @asyncinnovator/hallint-cli ./src --rules all
npx @asyncinnovator/hallint-cli ./src --no-color
| Option | Description | Default |
|---|---|---|
--rules |
||
Rule set: recommended or all |
||
recommended |
||
--min-severity |
||
Minimum severity: critical high medium low info |
||
info |
||
--no-color |
||
| Disable colored output | off | |
--help |
||
| Show help | ||
--version |
||
| Show version |
| Code | Meaning |
|---|---|
0 |
|
| No issues found | |
1 |
|
| One or more critical or high findings | |
2 |
|
| Unexpected error |
import { scan } from '@asyncinnovator/hallint'
const result = await scan({
files: ['./src/**/*.ts'],
})
result.findings.forEach(f => {
console.log(`${f.severity} [${f.ruleId}] ${f.filePath}:${f.line}`)
console.log(` ${f.message}`)
console.log(` fix: ${f.fix}`)
})
js
const result = await scan({
files: ['./src/**/*.ts'],
rules: 'recommended',
minSeverity: 'high',
ignore: ['**/node_modules/**', '**/dist/**'],
})
js
import { scanSource } from '@asyncinnovator/hallint'
const source = `const apiKey = "sk-abc123def456ghi789jk"`
const findings = scanSource(source, 'example.ts')
findings.forEach(f => console.log(f.ruleId, f.message))
{
findings: Finding[] // all issues found
scannedFiles: string[] // list of files scanned
durationMs: number // time taken
summary: { // count per severity
critical: number
high: number
medium: number
low: number
info: number
}
}
{
ruleId: string // e.g. "hardcoded-secret"
severity: string // "critical" | "high" | "medium" | "low" | "info"
message: string // human-readable description
fix: string // suggested fix
filePath: string // absolute path to the file
line: number // line number
snippet: string // the offending line of code
}
| Rule | Severity | What it catches |
|---|---|---|
hardcoded-secret |
||
| critical | API keys, tokens, passwords in source code | |
sql-injection |
||
| critical | User input interpolated into SQL queries | |
unsafe-eval |
||
| critical | eval() or new Function() with dynamic input |
|
missing-auth-check |
||
| high | Route handlers with no auth middleware | |
xss-innerHTML |
||
| high | Unsanitized strings assigned to innerHTML |
|
permissive-cors |
||
| high | cors({ origin: '*' }) in route handlers |
|
async-no-catch |
||
| medium | async functions with no try/catch or .catch() |
|
http-not-https |
||
| medium | Hardcoded http:// URLs in fetch or axios calls |
Create a hallint.config.ts
at your project root:
import type { ScanConfig } from '@asyncinnovator/hallint'
export default {
rules: 'recommended',
minSeverity: 'medium',
ignore: [
'**/node_modules/**',
'**/dist/**',
'**/*.test.ts',
],
} satisfies Omit<ScanConfig, 'files'>
Add hallint as a PR gate — it exits with code 1
on any critical or high finding:
name: hallint
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
hallint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npx @asyncinnovator/hallint-cli ./src --min-severity high
Install husky:
npm install --save-dev husky
npx husky init
echo "npx @asyncinnovator/hallint-cli ./src --min-severity high" > .husky/pre-commit
Contributions are welcome. Each rule is a single file (~30 lines) with a bad.ts
/ good.ts
fixture — a new rule is a good first contribution.
-
Fork the repo
-
Create a branch:
git checkout -b feat/rule-your-rule-name -
Add your rule in
packages/core/src/rules/index.ts -
Add fixtures in
packages/core/tests/fixtures/your-rule-name/ -
Run tests:
npm test -
Open a PR
Issues labeled good first issue are pre-scoped and ready to pick up.
MIT — free to use in personal and commercial projects.