# hallint Update: What We Fixed, What We Shipped, and What's Coming in v0.2

> Source: <https://dev.to/asyncinnovator/hallint-update-what-we-fixed-what-we-shipped-and-whats-coming-in-v02-35l7>
> Published: 2026-07-14 11:36:38+00:00

*This is a follow-up to I Built a Linter That Catches the Security Bugs AI Assistants Keep Writing. The comments on that post shaped most of what's in this update — thank you.*

The first post got a lot of honest feedback. Not just "cool project" — actual technical pushback on the things that weren't right yet. This post covers what we fixed based on that, what's shipped since, and what's coming in v0.2.

Current versions:

`@asyncinnovator/hallint`

— `@asyncinnovator/hallint-cli`

— Two issues came up repeatedly and they were both valid.

**1. async-no-catch was polluting the signal.**

[Nazar Boyko](https://dev.to/nazar-boyko) put it cleanly: the rule breaks the bar of "a human looking at the flagged line agrees it's wrong." Plenty of correct async code has no try/catch because the caller handles it, or because an Express error middleware catches it upstream. Running hallint on a real codebase and getting forty `async-no-catch`

warnings next to one genuine hardcoded key destroys the signal you worked to build.

**Fix shipped:** `async-no-catch`

is now removed from the `recommended`

ruleset. It still exists and still runs if you opt in with `--rules all`

, but it no longer fires by default. The seven security rules that share the "this line is wrong" property remain in `recommended`

.

**2. missing-auth-check had a false positive problem on intentionally public routes.**

[Dipankar Sarkar](https://dev.to/dipankar_sarkar) and [Adam Lewis](https://dev.to/nark3d) both flagged this. Health checks, webhooks, public endpoints — they're supposed to have no auth middleware. Flagging them is noise, and noise gets the rule disabled.

**Fix shipped:** hallint now recognizes three inline suppression markers:

```
// public
// hallint-public
/* hallint-public */
```

Add any of these to a route and hallint skips the auth check on that handler. Clean, explicit, no magic inference needed.

``` js
app.get('/health', (req, res) => { // hallint-public
  res.json({ status: 'ok' })
})
```

`hardcoded-secret`

now runs dual-pass detection.

The original regex caught generic `api_key = "..."`

patterns. It missed token prefixes that are dead giveaways regardless of variable name. The rule now has a second pass targeting known prefixes: `ghp_`

, `sk-`

, `AKIA`

, `xoxb-`

. A line containing any of these is flagged as critical even if the variable name looks innocent. Comments and env-var assignments are excluded.

`sqlInjection`

message copy was over-claiming.

The original message said "user input flowing into query" but the detection was pattern-based, not data-flow-based. It couldn't actually prove the variable was user input — just that a template literal was used inside a query call. The message now reflects what the rule actually detects: template literal interpolation in a query call. Accurate scope, no false confidence.

**Scanner dispatch was refactored.**

Previously, the scanner used `rule.layer`

to decide whether to run regex or AST matching. This meant rules had to set `layer`

correctly or they'd be silently skipped. Now `rule.match()`

presence is the dispatch signal — if a rule has a `match()`

function it gets AST treatment, otherwise regex. `layer`

is now metadata only, used for documentation and filtering. This makes rule authoring less error-prone.

`asyncNoCatch`

detection was fragile.

The brace-counter approach used to find async function boundaries broke on nested objects and template literals with braces. Replaced with a `stripStrings()`

heuristic that removes string content before counting — significantly fewer false positives even before the rule was moved out of `recommended`

.

You can now gate CI on hallint in five lines:

```
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
  with:
    node-version: 20
- run: npx @asyncinnovator/hallint-cli ./src
```

hallint exits `1`

on critical or high findings, so this blocks merges on real issues. The LLM layer — when it lands — will never trigger exit code `1`

. Non-deterministic checks don't belong in CI gates.

A few things were promised in the comments and are actively in progress.

**Cross-file router composition tracking.**

Right now `missing-auth-check`

is same-file only. If your middleware is registered in `app.ts`

and your routes live in `routes/users.ts`

, hallint doesn't connect them. This is the honest limitation of regex-based analysis — you can't follow imports. v0.2 introduces tree-sitter for AST analysis, which makes cross-file tracking possible. This is the main structural change in v0.2.

**LLM layer — opt-in only.**

The optional LLM review pass will land in v0.2 as a strict opt-in: `--llm ollama`

or `--llm anthropic`

. It will never run by default and will never contribute to exit code `1`

. As Kartik noted in the comments, non-determinism in a CI gate is a dealbreaker. The LLM layer surfaces things the regex and AST layers miss — semantic issues, logic flaws, context-blind patterns — but those findings go in a separate output section, not in the main results that block a merge.

**New rules under consideration for v0.2–v0.3:**

`silent-error-swallow`

— bare catch blocks that swallow errors without logging or rethrowing. The pattern Edu Peralta described: looks handled, isn't.`jwt-in-localstorage`

— storing tokens where XSS can reach them`hallucinated-dependency`

— imports of packages that don't exist in package.json (a real AI-specific failure mode)
Each rule is a single file, around 30 lines, with a `bad.ts`

and `good.ts`

fixture. If you've seen a pattern AI assistants keep producing that hallint doesn't catch yet, the path from "I noticed this" to "I shipped a fix" is short.

Issues labeled **good first issue** are pre-scoped and ready to pick up.

**GitHub:** [github.com/Asyncinnovator/hallint](https://github.com/Asyncinnovator/hallint)

```
npx @asyncinnovator/hallint-cli ./src
```

MIT licensed. Free for personal and commercial use.
