Open-source project
anordal/shellharden avatar
anordal/shellharden

shellharden: the bash quoting tool that can fix, not just complain

The corrective bash syntax highlighter

4,809 stars133 forksRustMPL-2.0

At a glance

What is it?
A Rust implementation of a corrective syntax highlighter that shows proposed quoting changes as background colors, and can apply them when you tell it to. Deliberately not a substitute for review.
Who is it for?
Shellharden occupies a real gap: ShellCheck detects unsafe quoting and explains it, but nothing in that workflow can say yes on your behalf, and a large enough legacy script will not be fixed by hand.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 90 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A syntax highlighter where the background color matters

The default mode of Shellharden behaves like `cat`, with one important difference: foreground colors carry syntax highlighting and background colors carry a diff. Green marks characters the tool would add, red marks characters it would remove, if you let it loose with the `--transform` option.

That design decision is what makes the tool reviewable rather than magical. A tool that silently rewrote a thousand-line deployment script would be unusable, and one that printed a traditional diff would throw away the parsing work that makes the highlighting possible in the first place. Coloring the live input keeps the parsed structure on screen, so you can see quoting in the context of the command it belongs to.

The README's real-world example is a selected portion of `xdg-desktop-menu`, which is a better demonstration than an artificial snippet because it shows the tool handling someone else's production script. A second example exists specifically to cover trickier cases and special features.

The description in the repository metadata is The corrective bash syntax highlighter, and that word corrective is the summary of the whole project.

Why quoting is the whole problem

The README opens its justification with an image rather than a benchmark: a variable in bash is like a hand grenade, take off its quotes and it starts ticking. Hence rule zero of the bash pitfalls page the README links to, always use quotes.

That is the entire threat model. Unquoted variables and command substitutions undergo word splitting and glob expansion, so a filename with a space in it becomes two arguments, a filename with an asterisk in it matches other files in the directory, and a value that happens to contain a leading dash can be read as an option by the command receiving it. None of these are exotic; they are what happens when ordinary data arrives from outside the script.

The README also names the project's prior art and positions it carefully. ShellCheck is described as a wonderful tool to detect vulnerable bash code and give general advice about it, with one thing missing: something to say yes with and apply that advice, assuming proper review of course.

The author also explains why a syntax highlighter was built into the tool rather than kept separate. The original request was a tool that could rewrite bash scripts with proper quoting, and the answer he wanted was a syntax highlighter in the same tool, as a way to see if the parser gets lost and to get the most out of the parser. The stated reason is worth quoting because it explains the architecture: bash is like quantum mechanics, nobody really knows how it works.

Installing from crates.io and building from source

The official Rust package is on crates.io, and there is a repology badge for distro packages.

bash
cargo install shellharden

Building from source is the usual two steps, and the install step puts the binary where a personal install expects it.

bash
cargo build --release
mv target/release/shellharden ~/.local/bin/

That move into `~/.local/bin` implies a PATH entry for that directory, which is a reasonable default for a single developer tool and one you may already have.

The project is written in Rust and the manifest confirms it. `Cargo.toml` names the package shellharden at version 4.3.2, authored by Andreas Nordal, licensed MPL-2.0, on edition 2015. Edition 2015 for a Rust project that is still shipping is unusual enough to be worth noticing, though the project has no business being modern Rust in the way the language is usually modernized.

The repository is small and coherent: `src/`, `tests/`, `moduletests/`, `docker/`, `img/`, a `CHANGELOG.md`, a `TODO.md` and the aforementioned `how_to_do_things_safely_in_bash.md`. The presence of a `docker/` directory suggests a containerised route for CI or for trying it without installing, and `moduletests/` is where the module-level test fixtures live, which is also the seed corpus for fuzzing.

Testing, coverage and fuzzing, which is unusual for a linter

Most linting tools ship tests and stop there. This one also documents a coverage workflow and an American fuzzy Lop fuzzing setup, and both are worth reading because they explain how much the parser is trusted.

bash
cargo test
env RUSTFLAGS="-C instrument-coverage" LLVM_PROFILE_FILE='run-%m.profraw' cargo test
grcov . --binary-path ./target/debug/ -s . -t html -o ./coverage/

Plain `cargo test` is annotated as requiring bash, which makes sense for a tool that parses and rewrites shell scripts and needs a shell to check behaviour against. The coverage variant instruments the binary, writes per-module profile files, renders them to HTML with `grcov` and then removes the raw profiles, with the last step opening the report in a browser.

The fuzzing setup installs `cargo-afl`, builds with it and then fuzzes the binary using `moduletests/original` as the input corpus.

bash
cargo install cargo-afl
cargo afl build --release
cargo afl fuzz -i moduletests/original -o /tmp/fuzz-shellharden target/release/shellharden ''

That fuzz target deserves attention as a design statement. The tool takes shell scripts as input, and feeding it malformed and hostile input is how you find out whether a bash parser can be made to loop, allocate without bound or panic. The empty string argument in the command is the value being highlighted. Using the module test originals as the seed corpus means the fuzzer starts from realistic scripts rather than random bytes.

The transform warning, which is the most important paragraph

The README has a Usage advice section and it is worth reading before running the tool on anything you care about. The instruction is direct: do not apply `--transform` blindly, because code review is still necessary.

The reason is behavioural rather than stylistic. A script that relies on unquoted behavior, meaning implicit word splitting and glob expansion from variables and command substitutions, will do none of that after getting the `--transform` treatment. The script still runs, and it now runs differently, which is the worst possible failure mode for a security tool.

The author's follow-up is constructive rather than defensive. In that unlucky case, ask whether the script has any business doing that, since this reliance is often just a product of classical shellscripting and would be better rewritten, for example by using arrays. And even where the business logic genuinely involves word splitting, that can still be done without invoking globbing.

The summary is that there is always a better way than the forbidden syntax, if not more explicit, but sometimes a human has to step in and rewrite. The accompanying document, `how_to_do_things_safely_in_bash.md`, exists for that rewrite.

There is an explicit responsibility statement as well: the builtin assumption is that the script does not depend on the vulnerable behavior, and the user is responsible for the code review. The tool is not claiming to make a script safe by running it through itself.

A name change, a licence, and how active this is

Shellharden was previously known as Naziquote. The author's comment on the old name is that in the right jargon it was the best name ever, but it was misleading and unspeakable to outsiders. He also considered calling it a bash cleaner and rejected that on the grounds that it means poo smearer in Norwegian. Those two sentences tell you a fair amount about the project's tone, which is candid to the point of self-deprecation.

The licence is MPL-2.0, the file-level copyleft Mozilla licence, which matters if you intend to distribute a modified binary: your changes to covered files must stay under the same licence.

On activity, the last push to master was on 2026-07-09, which is recent enough to describe plainly. The two releases in the list are v4.3.2 from 2026-06-27 and v4.3.1 from 2024-03-24, and both have empty release bodies, which tells you the changelog lives in the `CHANGELOG.md` file rather than in GitHub releases. That gap between the two dates also suggests the project ships on its own schedule rather than on a cadence, so version numbers move when there is something to release.

The repository is not archived, has 10 open issues and 4,806 stars, which for a single-purpose tool with one author is a healthy signal. The topics are lint, policy and syntax-highlighter, the last of which is a clue about how the author positions it: this is presented as a policy tool that happens to render as a highlighter.

Editorial conclusion

Shellharden occupies a real gap: ShellCheck detects unsafe quoting and explains it, but nothing in that workflow can say yes on your behalf, and a large enough legacy script will not be fixed by hand. Here the suggested changes are visible as background colors before anything is written, so reviewing a transform is reading a diff, and the honest constraint is the one the README states plainly, that a script which depends on unquoted word splitting or globbing will change behaviour. Run it without `--transform` first, read the highlights, then transform a copy. For anything the transform cannot express, the bundled document on doing things safely in bash is the more valuable read.

Frequently asked questions

What is the difference between shellharden and ShellCheck?

ShellCheck detects unsafe bash and gives general advice, while Shellharden can apply the suggested changes. The README frames ShellCheck as a wonderful detection tool whose only missing piece is something to say yes with. Shellharden focuses mainly on quoting and leaves the code review to you.

How do I install shellharden?

The official package is on crates.io, so `cargo install shellharden` is the supported route, and repology tracks distro packages. To build from source, run `cargo build --release` and then move `target/release/shellharden` into `~/.local/bin/`.

What does the green and red background coloring in shellharden mean?

Foreground colors are ordinary syntax highlighting. The background colors are the diff: green marks characters Shellharden would add and red marks characters it would remove if you ran it with the `--transform` option. That is what makes reviewing a transform a matter of reading the highlighted input rather than reading a separate patch.

Is it safe to run shellharden with --transform on a script?

Not without review. The README warns against applying the transform blindly, because a script that relies on unquoted word splitting or glob expansion will stop doing that and will still run. The stated assumption is that the script does not depend on the vulnerable behavior, and the user is responsible for checking that.

What was shellharden called before, and what licence is it under?

It was previously known as Naziquote, a name the author now considers unspeakable to outsiders. The licence is MPL-2.0, declared in both the repository metadata and `Cargo.toml`, and the package description remains The corrective bash syntax highlighter.

Does shellharden have tests?

Yes, and the README documents more than the usual unit tests. `cargo test` runs the suite and requires bash, coverage can be measured with an instrumented build plus `grcov`, and there is an AFL fuzzing setup that starts from the originals in `moduletests/original` as its seed corpus.

Official sources

  1. anordal/shellharden on GitHub
  2. Issues
  3. License: MPL-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/anordal-shellharden.svg)](https://hysenlabs.com/projects/anordal-shellharden)