npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tauri-audit

v0.1.1

Published

Static security analyzer for Tauri v2/v1 apps — separates severity from confidence, keeps high-confidence false positives at zero.

Readme

tauri-audit

日本語の入口は README.ja.md にあります。

Static security analyzer for Tauri v2 and v1 apps. It parses your configuration and source without running the app, so it is fast, safe, and CI-friendly.

Status: pre-release (0.1.1). Eight rules, landing incrementally. See Roadmap.

Unofficial. An independent project, not affiliated with or endorsed by the Tauri project or the Tauri Programme within the Commons Conservancy.

Where this fits

tauri-audit is complementary to, not a replacement for, the dependency scanners you already run:

| Concern | Tool | | --- | --- | | Insecure configuration — dangerous flags, over-broad capability scopes, missing CSP | tauri-audit | | Vulnerable Rust dependencies | cargo-audit / RustSec | | Vulnerable npm dependencies | npm audit | | General-purpose code patterns across any language | Semgrep, CodeQL |

Semgrep and CodeQL analyze code; tauri-audit analyzes the configuration that decides what that code is permitted to do. Neither knows what dangerousDisableAssetCspModification means or that $CONFIG/** is a different grant from $APPCONFIG/**.

tauri-audit does check a small number of Tauri-specific advisories where the vulnerability only matters in combination with your configuration (so a plain version bump check would be misleading), but wholesale dependency auditing is not its job.

Lockfile support. A manifest records a version range; only a lockfile records what is installed. Cargo is the sharpest example: tauri-plugin-shell = "2.2.0" means ^2.2.0 and almost certainly installs the patched 2.2.1, so reading it as "2.2.0, vulnerable" flags a project that is fine.

| Lockfile | Support | | --- | --- | | Cargo.lock, package-lock.json, pnpm-lock.yaml (v5/v6/v9) | resolved versions read — findings are confirmed | | yarn.lock, bun.lock*, unrecognized pnpm-lock.yaml versions | not parsed — findings fall back to manifest ranges and are reported as possible | | no lockfile | manifest ranges only — possible |

The fallback errs toward reporting: a range that could include an affected version is flagged, and the finding says the installed version is unknown. Nothing is hidden.

It accepts false negatives to avoid false positives. Rules whose exemption conditions cannot be verified statically are reported as heuristic and never fail your build by default. See Honest limitations.

Install

npm install -g tauri-audit
# or run it without installing
npx tauri-audit ./my-tauri-app

Requires Node.js >= 22.12.

Usage

tauri-audit <target-path> [options]

| Option | Effect | | --- | --- | | --json | machine-readable JSON output | | --markdown | Markdown report | | --sarif | SARIF 2.1.0, for GitHub code scanning | | --category <id> | SARIF category (run.automationDetails.id) | | --strict | also fail on heuristic critical/high findings | | --no-fail | do not fail on findings (operational errors still exit 2) |

Severity and confidence are separate

Every finding carries two independent values:

  • severity — critical / high / medium / low / info: how bad this is if real.
  • confidence — high / heuristic: how sure we are that it is real.

They do not collapse into one number. A critical issue we can only suspect stays heuristic. This matters because several Tauri CVEs carry exemption conditions ("not affected if…") that cannot be cross-checked statically — those rules are pinned to heuristic permanently and their finding text tells you how to confirm by hand.

For CVE-derived rules, severity follows the GitHub Security Advisory label as the primary source. Where scoring sources disagree — CVE-2023-46115 is GHSA Low, NVD 5.5 Medium, and CNA 8.4 High — the finding cites all of them rather than picking one.

Exit codes (CI gate)

| Code | Meaning | Suppressed by --no-fail? | | --- | --- | --- | | 0 | analysis completed; nothing gated | — | | 1 | gating findings present | yes | | 2 | operational error, or the analysis could not fully cover the project | no |

"Gating" means high-confidence critical or high by default; --strict widens it to include heuristic findings of those severities.

This exact predicate is also the pass condition of the clean-corpus regression test, so "the tool would not break this app's CI" has one definition, checked in one place.

What the corpus result actually says

Two claims live here, and they are not the same claim:

  • Nineteen applications produce zero high-confidence findings. This is what "no false positives" means, and it holds for all nineteen. Seventeen are third-party — chosen on licensing and provenance, never on what a rule would say about them — and two are Tauri's own v1 examples.
  • Seventeen of the nineteen are analyzed completely. The other two are those Tauri examples: they carry a tauri.conf.json and no Cargo.toml, because upstream keeps their Rust manifests elsewhere. Their dependency rules therefore examined nothing, so those runs exit 2 rather than 0, and say why.

A further six applications sit in tests/corpus/true-positive/, where a rule fires and is right to. They are not failures of the corpus but its output: four arrived through the same selection process as the nineteen and were moved only after the finding was examined and judged correct.

Eliding the difference would be the same mistake this tool refuses to make about its own output. Per-application coverage is recorded in tests/corpus/, next to the findings.

Unanalyzable is not clean

Exit 2 covers more than bad flags. If a config could not be parsed, could not be placed as v1 or v2, was skipped for size, or does not exist at all, then no rule ran over it — and "zero findings" would be silence, not safety. tauri-audit refuses to report that as success: it prints what it could not analyze and exits 2.

--no-fail is a statement about findings ("do not block my build over what you found"), not a claim that the run succeeded, so it does not suppress this. If you point tauri-audit at a directory with no Tauri project, you get 2, not a clean bill of health.

GitHub Action

- uses: gyugyu86/[email protected]
  with:
    path: .
    version: 0.1.1          # pin the scanner (default: latest)
    category: tauri-audit   # give each run its own category

@v0.1.1 is the recommended pin. For the strongest supply-chain guarantee, pin the commit SHA the tag resolves to instead — an author can move a tag, but not a commit SHA. Run git rev-parse v0.1.1^{commit} and use uses: gyugyu86/tauri-audit@<sha> # v0.1.1.

Pin the scanner too. The version: input defaults to latest, so pinning only the action does not pin the scanner — the action runs npx tauri-audit@<version>, which resolves against npm at run time. A scan can then change without your workflow changing. Set version: explicitly, as above, so the action and the scanner move together.

The scan step never fails on its own, so the SARIF always reaches the Security tab; the gate is a separate step.

Rules

Rule documentation lives in the finding text itself — each finding explains why the setting is dangerous and how to confirm or fix it, so the report is readable without this table.

| ID | Applies to | Detects | Severity / confidence | Evidence | | --- | --- | --- | --- | --- | | TA-CONF-001 | v1 + v2 | security.csp unset or null — no policy is enforced | medium / heuristic | real-world | | TA-CONF-002 | v1 + v2 | security.dangerousDisableAssetCspModification | true → high / high · directive list → medium / heuristic | synthetic | | TA-V1-001 | v1 | tauri.allowlist.all: true — every v1 API enabled at once | high / high | real-world | | TA-V1-002 | v1 | tauri.security.dangerousRemoteDomainIpcAccess — remote origins granted IPC | enableTauriAPI or plugins → high / high · domain-only → medium / heuristic | synthetic | | TA-V1-003 | v1 | tauri.security.dangerousUseHttpScheme: true | medium / high | synthetic | | TA-DEP-001 | v2 | shell plugin ≤ 2.2.0 with an unset open scope (CVE-2025-31477) | high / heuristic | synthetic | | TA-VITE-001 | any | Vite envPrefix covering Tauri signing variables (CVE-2023-46115) | low / heuristic | synthetic | | TA-CAP-003 | v2 | capability filesystem scope reaching past the application | medium / heuristic | real-world |

Evidence records whether the rule has been shown to fire on real third-party code, and is carried as rule metadata rather than documentation, so a test can check it. real-world means the rule fires on an unmodified config vendored in tests/corpus/; synthetic means it has only been demonstrated against fixtures written for this repository. A rule may understate its evidence but cannot claim real-world without a corpus application to back it — that direction is asserted in the suite.

Firing on an application in clean/ still counts, and is worth reading carefully: it proves the rule matches real code, and it simultaneously proves the rule must stay heuristic, since a high-confidence finding there would fail those projects' builds. That is the position TA-CONF-001 is in.

Most rules are synthetic because the settings they look for are rare in shipped code — which is the point of them being dangerous. That asymmetry is expected rather than a gap to close, and tests/corpus/README.md lists exactly which rules still lack real-world material.

What this is worth on v2, honestly

Most of the deterministic rules above are v1-only, and that is a fact about Tauri rather than about coverage. v1's allowlist was opt-in but coarse, and it carried explicit dangerous* switches that a project could turn on. v2 replaced it with capabilities, which are default-deny and per-command — so there are simply fewer settings left that are wrong under every reading.

The value on v2 is therefore different in kind. It is not "find the dangerous flag"; it is making capability grants reviewable: noticing that a filesystem scope reaches past the application, that a CVE's exemption cannot be confirmed, that no CSP is set. Those are judgement calls surfaced for a human, which is why the v2 rules are heuristic and why they do not gate. If you are on v2 and this tool reports nothing gating, that is the expected result and largely a credit to v2's design.

About the applications in true-positive/

tests/corpus/true-positive/ holds real configurations that trip a rule. They are there as evidence that the rules detect something, which is the claim the clean corpus cannot make. Neither entry is a report about an application being insecure.

Tauri's own examples/api trips TA-V1-001 by setting allowlist.all: true. That is not a defect in Tauri: it is an API demonstration whose purpose is to exercise every API in one place, so enabling all of them is correct for what it is and wrong only if copied into a product.

KiwiTalk trips the same rule. It is included as a case where the pattern this rule detects appears in a real application — nothing more. What the finding states is a fact about a public configuration file: allowlist.all: true enables every v1 API family at once. Whether that is reachable in that application depends on its frontend, which this tool does not analyze, and no claim is made about it.

Both are here for the same reason: a permissively licensed configuration written by people who know the framework is far better evidence than a fixture written by whoever wrote the rule.

Polarity is decided per rule, from the primary source. For most rules above the dangerous state is a setting explicitly turned on, so an absent key is safe. Two are the exact inverse. TA-DEP-001 treats an unset plugins.shell.open as affected, because the default validation an unset value selects is the part that was broken. TA-CONF-001 fires when no CSP is configured, because the field defaults to null and a null CSP enforces nothing. Assuming the familiar polarity in either case would have missed the entire affected population.

TA-CONF-001 therefore fires on a large share of real applications, which is intended: it is medium/heuristic and can never fail a build. Five of the ten corpus applications ship without a CSP, and reporting that is correct rather than a false positive.

Two of these grade themselves by content rather than by presence. dangerousDisableAssetCspModification: true switches Tauri's CSP rewriting off entirely, while a directive array narrows it — the same key, two different settings, so they are not reported the same way. Likewise a remote-IPC entry granting enableTauriAPI hands over the whole API surface, whereas one naming only a domain and windows enables the mechanism without granting commands through that setting alone, and what those windows expose otherwise is not visible in the config.

More rules are landing — see Roadmap.

Honest limitations

These are deliberate. A static analyzer that fails CI on its own false positives is one nobody keeps in their pipeline.

  • The app is never executed. Configuration is parsed, not evaluated. Anything decided at runtime is invisible.
  • Exemption conditions are respected by downgrading, not by guessing. Where an advisory says "not affected if X" and X cannot be checked statically, the rule stays heuristic and the finding tells you how to verify X yourself.
  • Line numbers are exact for JSON, approximate for JSON5 and TOML. tauri.conf.json and capabilities/*.json are parsed with position information; tauri.conf.json5 and Tauri.toml fall back to a key scan and may point at the enclosing region.
  • Mixed or unrecognizable configs are skipped, not guessed. If a document cannot be confidently placed as v1 or v2, no config rules are applied to it and a warning is logged — applying v1 rules to a v2 config (or the reverse) is a pure false-positive source.
  • vite.config.* is read by text scan, not parsed. There is no JavaScript parser in this package yet, so a envPrefix built from variables, spread from another object, or written as a template literal is not analyzed and produces no finding. Comments and string literals are masked before the option is looked for, so a commented-out or quoted mention does not trigger it either.
  • There is no dataflow analysis yet. Nothing tracks a value from a source to a sink, so a rule cannot tell whether attacker-controlled input reaches a dangerous call. When it lands (Phase 3) it will be single-function-scope only: cross-function flow, return values and reassignment will not be followed, which trades false negatives for false positives deliberately.
  • Rust source analysis is not implemented yet (planned, tree-sitter based).
  • Lockfiles: Cargo.lock, package-lock.json and pnpm-lock.yaml (v5/v6/v9) give confirmed versions; yarn.lock and bun.lock* are recognized but not parsed, so those projects fall back to manifest ranges and their dependency findings say so.
  • Evidence strength differs per rule, and each rule says which it has — see the Evidence column above.

Roadmap

  • Phase 1 (MVP) — configuration rules, TypeScript only. Deterministic rules first to establish the zero-false-positive pipeline, then CVE and context-dependent rules as heuristic.
  • Phase 2 — JavaScript/TypeScript AST rules (invoke, shell.open).
  • Phase 3 — Rust analysis via tree-sitter, single-function-scope dataflow, heuristic only.

Development

npm ci
npm run build   # tsc; no bundler
npm run lint
npm test        # all layers, fully offline

The analysis engine (src/core/) knows nothing about the CLI (src/cli/); the dependency runs one way only, so the engine stays embeddable.

License

MIT. See LICENSE.

Test fixtures under tests/corpus/ are third-party configuration files retained under their own licenses; each directory carries a PROVENANCE.md recording its source, commit, and license. They are test data, not part of the distributed package (npm ships dist/ only).