Skip to content

Instantly share code, notes, and snippets.

@stevencarpenter
Created April 10, 2026 08:49
Show Gist options
  • Select an option

  • Save stevencarpenter/8d52f32c038c45968c83bb8e40eaf76a to your computer and use it in GitHub Desktop.

Select an option

Save stevencarpenter/8d52f32c038c45968c83bb8e40eaf76a to your computer and use it in GitHub Desktop.
Spam Slop afadesigns/zshellcheck

Investigation Report: afadesigns/zshellcheck

Date: 2026-04-10 Repo: https://github.com/afadesigns/zshellcheck Trigger: Google Gemini AI Overview recommends this tool as a "dedicated static analysis tool designed specifically for the Zsh ecosystem" when users search "shell check for zsh."


Executive Summary

ZShellCheck is a solo-developer Go project that claims to be "the definitive static analysis and comprehensive development suite for the entire Zsh ecosystem." Investigation reveals a pattern consistent with AI-assisted development optimized for metric inflation rather than genuine utility. The project has no meaningful community adoption, an automated versioning scheme that produces misleading version counts, and a pre-commit hook that compiles arbitrary Go code on your machine from an unreviewed source. It should not be used, and its recommendation by Google Gemini's AI Overview is a failure of that system's source evaluation.


1. Repository Vital Signs

All data sourced via GitHub API on 2026-04-10.

Metric Value Source
Created 2025-11-12 repos/afadesigns/zshellcheck .created_at
Age ~5 months
Stars 12 .stargazers_count
Forks 3 .forks_count
Subscribers (watchers) 1 .subscribers_count
Open issues 7 .open_issues_count
Actual issues (non-PR) 1 filtered via API
Total commits 588 pagination header page=588
Total PRs 286 pagination header page=286
Total tags 226+ paginated tag listing (3+ pages of 100)
GitHub Releases 0 releases endpoint returned empty
Contributors 1 real (afadesigns: 587 commits), 1 token (redteamx: 1 commit) repos/.../contributors
External PRs (non-owner, non-bot) 1 (from norwd, still open) filtered PR listing

Owner Profile

Field Value
Username afadesigns
Bio "Bringing ideas to life through visually captivating designs and interactive experiences"
Public repos 4
Followers 5
Account created 2024-03-03
Other repos afadesigns (2 stars), envkeep (2 stars), pyru (2 stars)

This is a designer with no visible background in compilers, static analysis, or shell internals.

The redteamx Account

The CI workflow tag-release.yml uses a PAT secret named REDTEAMX_PAT. The user redteamx has 1 commit in the repo and forked it on 2025-11-29.

Field Value
Username redteamx
Bio (none)
Account created 2025-03-03
Public repos 3
Followers 2

Likely the owner's alt account or close collaborator. The PAT is used specifically because GitHub Actions' GITHUB_TOKEN doesn't trigger downstream workflows — this is a workaround to chain the auto-tagger into the release workflow.


2. Version Inflation Mechanism

How it works

The file .github/workflows/tag-release.yml (SHA 55391ab) contains:

- name: Bump version and push tag
  uses: anothrNick/github-tag-action@a2c70ae1...  # 1.69.0
  env:
    GITHUB_TOKEN: ${{ secrets.REDTEAMX_PAT }}
    WITH_V: true
    DEFAULT_BUMP: patch

This runs on every push to main. Every merged PR automatically increments the patch version. There is no human decision about what constitutes a release.

The result

  • 226 tags in 5 months = ~1.5 tags per day average
  • 0 GitHub Releases — there are no release notes, no binaries, no changelogs tied to tags
  • README says v0.1.66 ("166 Katas") but the latest tag is v0.1.226 and the latest PR mentions "277 katas" — the README is not maintained to match the automated version counter

Why this matters for pre-commit users

The pre-commit hook config in the README suggests pinning to rev: v0.1.66. But the actual tags are a continuous stream. Users have no way to evaluate what changed between versions because there are no release notes. Each "version" is typically a single self-merged PR.


3. Commit Velocity Analysis

Burst patterns

Date Commits Time span Rate
2026-03-31 85 03:19 - 15:33 UTC (~12 hrs) 1 commit every 8.5 minutes
2026-04-07 12 01:12 - 01:54 UTC (~42 min) 1 commit every 3.5 minutes

Commit message pattern

Every kata commit follows an identical template:

feat: Add ZCxxxx — [imperative description] (#NNN)

Examples from April 7 (all within 42 minutes):

  • feat: Add ZC1271 — use command -v instead of which (#298)
  • feat: Add ZC1272 — use install -m instead of separate cp and chmod (#299)
  • feat: Add ZC1273 — use grep -q instead of redirecting to /dev/null (#300)
  • feat: Add ZC1274 — use Zsh ${var:t} instead of basename (#301)
  • ...through ZC1280

Self-merge pattern

PR #307 (the most recent merged PR at time of investigation):

  • Created: 2026-04-07 01:52:25 UTC
  • Merged: 2026-04-07 01:54:19 UTC
  • Time to merge: 1 minute 54 seconds
  • Reviewer: none (self-merged by afadesigns)
  • Files changed: 3 (new kata file, test file, version bump)

This pattern is consistent across all 286 PRs. The PRs exist to trigger the auto-tagger, not for code review.


4. Code Quality Assessment

The parser is real but basic

The project does contain a legitimate Pratt parser (pkg/parser/parser.go, 7KB) with:

  • A lexer (pkg/lexer/)
  • AST types (pkg/ast/)
  • Token definitions (pkg/token/)
  • Prefix/infix parse functions for zsh constructs ([[ ]], (( )), process substitution, etc.)
  • A 68KB test file (parser_test.go)

This is non-trivial work. However:

The katas are shallow pattern matching

Each "kata" is a ~50-line Go function that checks one specific command pattern. Example from zc1280.go:

func checkZC1280(node ast.Node) []Violation {
    cmd, ok := node.(*ast.SimpleCommand)
    if !ok { return nil }
    ident, ok := cmd.Name.(*ast.Identifier)
    if !ok || ident.Value != "cut" { return nil }
    // ... check if args contain "-d." and "-f2"
}

This is a glorified grep: "if the command is cut and has -d. and -f2, suggest ${var:e}." Every kata follows this exact template. The 280 katas represent 280 such pattern matches — volume that can be (and likely was) generated by an LLM in bulk.

Comparison with ShellCheck

ShellCheck (https://github.com/koalaman/shellcheck) is a Haskell project with:

  • 14,000+ stars, 700+ forks
  • Deep semantic understanding of shell behavior (data flow, quoting contexts, word splitting)
  • Active since 2012 (14 years of development)
  • Hundreds of real-world contributors
  • Published in system package managers (apt, brew, etc.)
  • Does not natively support zsh (tracked at koalaman/shellcheck#809), but can be forced with --shell=bash

ZShellCheck's claim to be "the full Zsh equivalent of ShellCheck" is not supported by the evidence. ShellCheck performs deep semantic analysis; ZShellCheck performs command-name matching.


5. Security Trust Assessment

OpenSSF Scorecard: 9.5/10 — but misleading

The OpenSSF Scorecard (fetched 2026-04-10 from api.securityscorecards.dev) shows:

Check Score Notes
Code-Review 10 Self-merges count as "reviewed"
Maintained 10 Automated commits keep the repo "active"
CI-Tests 10 14 workflows exist
SAST 10 CodeQL workflow present
Fuzzing 10 Fuzz test file exists
Contributors 3 Almost entirely one person
CII-Best-Practices 0 No OpenSSF badge obtained
Signed-Releases -1 No releases found
Branch-Protection -1 Internal error

The high score is an artifact of automation, not genuine security posture. The Scorecard rewards presence of CI machinery, not effectiveness. A solo developer self-merging PRs in under 2 minutes scores "10" on Code-Review because the check counts whether PRs exist, not whether they received independent review.

Pre-commit hook risk

The .pre-commit-hooks.yaml specifies:

- id: zshellcheck
  name: ZShellCheck
  entry: zshellcheck
  language: go
  files: \.zsh$

language: go means pre-commit will compile and execute Go code from this repository on your machine. Combined with:

  • No binary releases (compilation is the only path)
  • Solo maintainer with no independent review
  • Automated versioning where any commit becomes a "release"
  • A PAT from an unknown redteamx account controlling the tag pipeline

This is a supply chain risk. Any malicious code pushed to main would be automatically tagged and served to anyone using the pre-commit hook.


6. Community and External Validation

Zero presence on discussion platforms

Searches for zshellcheck afadesigns on Reddit, Hacker News, and Lobsters returned zero results.

A web search for github.com/afadesigns/zshellcheck did not return the repo itself — only unrelated zsh projects. The repo has no organic search presence.

Zero mentions in zsh ecosystem lists

The project does not appear in:

Stargazer analysis

The 12 stargazers include:

  • afadesigns (the owner)
  • redteamx (the PAT account)
  • Stxzor (forked the repo)
  • norwd (the one external PR contributor)
  • 8 others with no further engagement

No evidence of astroturfing, but also no evidence of genuine adoption.


7. The Gemini AI Overview Problem

Google Gemini's AI Overview recommends ZShellCheck as a "dedicated static analysis tool designed specifically for the Zsh ecosystem" alongside ShellCheck. This recommendation appears to be based on:

  1. The README's self-description — which uses authoritative language ("definitive", "comprehensive", "meticulously engineered")
  2. The security badges — SLSA Level 3, OpenSSF Scorecard 9.5/10, codecov, Go Report Card
  3. The high commit/version velocity — which signals "actively maintained" to automated systems
  4. The SEO-optimized structure — comparison tables, installation guides, integration docs

None of these signals require actual users, community trust, or tool effectiveness. This is a textbook example of how LLM-based search systems can be gamed by metric inflation and badge accumulation. The tool has 12 stars and zero community discussion, yet it's being recommended alongside ShellCheck (36k+ stars, 14 years of development) to users searching for shell linting tools.


8. Conclusion

Question Answer
Is it malicious? No evidence of malicious payloads in reviewed code.
Is it useful? Marginally — the katas are real but shallow pattern matches, not deep analysis.
Is it trustworthy? No. Solo developer, no community review, automated version inflation, pre-commit compiles arbitrary Go.
Is it what it claims to be? No. It is not "the definitive static analysis suite for Zsh" or "the full Zsh equivalent of ShellCheck."
Should you use it? No. Use ShellCheck with --shell=bash for zsh scripts, accepting its limitations.
Should Gemini recommend it? No. The recommendation is based on surface signals that were trivially gamed.

Sources

All GitHub data retrieved via authenticated GitHub API (gh api) on 2026-04-10.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment