Skip to content
Security · Web apps

Tauri 2 desktop app, least privilege

Tauri 2 rules and a permissions skill: capabilities for named windows, scoped fs and http, no shell execute, a CSP kept, plus a checker that flags wide grants.

Verified install Not agent-tested v1.0.0 MIT updated taurirusttypescript
Equips
  • 1 1 Rules
  • 1 1 Skills
  • – 0 MCP

Tauri 2 replaced the old allowlist with capabilities and permissions, and agents adding a feature tend to reach for the widest grant that makes it work: fs:default for every window, shell execute, http without a URL scope, CSP set to null. This loadout follows Tauri's security docs: the frontend is untrusted, capabilities name their windows, file and HTTP permissions carry scopes, commands validate their arguments. A small Node script checks capability files and tauri.conf.json, and the verifier runs it on a clean and a permissive project.

What's in it

  • Capabilities for named windows, never "*" with fs, shell or http
  • Every fs and http permission carries an allow scope
  • No shell execute or spawn; shell:allow-open or the opener plugin instead
  • CSP kept in app.security.csp
  • Checker script with clear findings, tested by the verifier

You'll need

  • Tools: node, cargo
Level 1 · automated

Verification

Verified install

Checked at commit 03c1b98 · 9 passed, 0 failed, 1 not applicable

CheckResultWhat we found
Listinglisting.yaml matches the schema and declares every file in the folder. Pass
Schema valid; 5 files declared, none missing or extra
  • tested.status: untested (agent tests are separate from Level 1)
Files parseJSON parses; SKILL.md and .mdc front matter is valid YAML with the fields each agent needs; code fences are closed. Pass All 5 files parse; front matter valid
AdaptersCLAUDE.md imports @AGENTS.md, GEMINI.md imports @./AGENTS.md, and both match the generator. Pass
CLAUDE.md and GEMINI.md import AGENTS.md and are up to date
  • CLAUDE.md: matches the generator
  • GEMINI.md: matches the generator
Install pathsEvery file lands where each agent documents it, with no collisions, and the laid-out project is re-discovered correctly. Pass
Correct paths for all 6 agents; layouts re-discovered
  • Claude Code: 4 files, 1 skill in .claude/skills/
  • Codex CLI: 3 files, 1 skill in .agents/skills/
  • Cursor: 3 files, 1 skill in .agents/skills/
  • Gemini CLI: 4 files, 1 skill in .agents/skills/
  • Antigravity CLI: 3 files, 1 skill in .agents/skills/
  • GitHub Copilot: 3 files, 1 skill in .agents/skills/
MCP configmcp.json is structurally valid, converts to each agent's format, declares no literal secrets, and referenced packages exist on npm/PyPI. Not applicable No MCP servers in this loadout
Safety scanThe intake scanner finds no credentials, risky shell, hidden Unicode or prompt-injection wording, and the listing's network flag is honest. Pass
Clean: no credentials, risky shell or hidden text
  • Scanner intake-precheck/1: verdict clean; network no (listing says yes)
ReferencesLinks and file paths between the loadout's files resolve, including for each agent's installed layout. Pass 1 reference between files resolves for every agent
Size limitsFile count and sizes are within the submission limits; SKILL.md bodies stay under 500 lines. Pass
5 files, 6.5 KB total; largest skills/tauri-permissions/scripts/check-capabilities.mjs 2.6 KB
  • Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule
LicenceA recognised SPDX licence, with the licence text available. Pass MIT, by Agent Loadout; text in the repository LICENSE
Starter buildA minimal fixture project with the loadout applied installs and builds or type-checks, and the loadout's own code examples compile. Pass
The capability check passes a least-privilege Tauri 2 project and reports every problem in a permissive one: null CSP, wildcard windows, unscoped fs and http, shell execute and remote URLs with permissions
  • Applied 7 loadout files at every agent's paths
  • ✓ least-privilege project passes: node .agents/skills/tauri-permissions/scripts/check-capabilities.mjs good
  • ✓ permissive project is caught: bash -c node .claude/skills/tauri-permissions/scripts/check-capabilities.mjs bad; test $? -eq 1 && echo caught
  • Covers: Named windows, scoped fs permissions and shell:allow-open pass
  • Covers: A null CSP is reported
  • Covers: Wildcard windows with fs, shell or http, unscoped fs and http, shell execute and remote URLs with permissions are reported

What this means: a script checked the files themselves: they parse, they install where each agent looks, any MCP config is sound, the safety scan is clean, references between files resolve, and, where a free and repeatable fixture exists, a small starter project builds with the loadout applied. No AI agent was run. Per-agent results ("tested with agent") are separate and stay untested until an agent actually runs.

Install

Choose your agent. Run the commands from your project root, or download a zip already laid out in the right folders.

Claude Code reads CLAUDE.md (imports AGENTS.md with @AGENTS.md) and skills from .claude/skills/.

Download zip
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/tauri-desktop-app/1.0.0/AGENTS.md
curl -fsSL --create-dirs -o CLAUDE.md https://loadout.jnw-it.com/raw/tauri-desktop-app/1.0.0/CLAUDE.md
curl -fsSL --create-dirs -o .claude/skills/tauri-permissions/SKILL.md https://loadout.jnw-it.com/raw/tauri-desktop-app/1.0.0/skills/tauri-permissions/SKILL.md
curl -fsSL --create-dirs -o .claude/skills/tauri-permissions/scripts/check-capabilities.mjs https://loadout.jnw-it.com/raw/tauri-desktop-app/1.0.0/skills/tauri-permissions/scripts/check-capabilities.mjs
FileGoes to
AGENTS.mdAGENTS.md
CLAUDE.mdCLAUDE.md
skills/tauri-permissions/SKILL.md.claude/skills/tauri-permissions/SKILL.md
skills/tauri-permissions/scripts/check-capabilities.mjs.claude/skills/tauri-permissions/scripts/check-capabilities.mjs

Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.

Files

Rules AGENTS.md Tauri 2 security model, Rust command rules and checks. 31 lines
Download Raw
# AGENTS.md: Tauri 2 desktop app

Tauri 2 app: a web frontend (in `src/`) and a Rust core (in `src-tauri/`). The frontend is untrusted; the Rust side
decides what it may do.

## Commands
- Dev: `npm run tauri dev` (or the project's package manager). Build: `npm run tauri build`.
- Rust checks, from `src-tauri/`: `cargo fmt --check`, `cargo clippy -- -D warnings`, `cargo test`.
- Frontend checks: the project's lint, type-check and test scripts.
- Permissions check after any change to capabilities or `tauri.conf.json`:
  `node <skills dir>/tauri-permissions/scripts/check-capabilities.mjs src-tauri`.

## Security model
- Capabilities in `src-tauri/capabilities/` grant permissions to named windows. Grant the minimum; use the
  `tauri-permissions` skill for any change.
- Never `"windows": ["*"]` on a capability that grants file system, shell or HTTP access. Name the windows.
- File system and HTTP permissions always carry a scope (`allow` paths such as `$APPDATA/**`, or exact URLs).
- No `shell:allow-execute` or `shell:allow-spawn` unless the human asks; prefer `shell:allow-open` or the opener plugin.
- Keep a Content Security Policy in `app.security.csp`. Never set it to null to make something load.
- Remote URLs (`remote.urls`) get no command access unless the human approves each one.

## Commands (Rust)
- `#[tauri::command]` functions validate every argument. Paths from the frontend are resolved and checked against an
  allowed base directory before use. Return `Result<T, String>` or a serialisable error type, never panic.
- Long work runs async or on a background thread; the UI must not freeze.
- Secrets live in the Rust side or the OS keychain, never in frontend code or `localStorage`.

## Changes
- Adding a plugin: `npm run tauri add <plugin>`, then grant only the permissions you use and justify each in the report.
- Do not upgrade Tauri, plugins or the webview target as part of another change.
Adapter CLAUDE.md Imports AGENTS.md for Claude Code. 10 lines
Download Raw
# CLAUDE.md

@AGENTS.md

## Claude Code notes
- Skills from this loadout live in `.claude/skills/`: `tauri-permissions`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "Tauri 2 desktop app, least privilege" v1.0.0 — https://loadout.jnw-it.com/loadouts/tauri-desktop-app/ -->
Adapter GEMINI.md Imports AGENTS.md for Gemini CLI. 10 lines
Download Raw
# GEMINI.md

@./AGENTS.md

## Gemini CLI notes
- Skills from this loadout live in `.agents/skills/`: `tauri-permissions`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "Tauri 2 desktop app, least privilege" v1.0.0 — https://loadout.jnw-it.com/loadouts/tauri-desktop-app/ -->
Skill skills/tauri-permissions/SKILL.md Grant the narrowest permission, then check. 20 lines
Download Raw
---
name: tauri-permissions
description: Add or change Tauri 2 capabilities with least privilege (named windows, scoped fs and http permissions, no broad shell access, CSP kept) and run the capability check. Use when a feature needs a new plugin or permission.
---

# Tauri permissions

1. Name the exact API the feature needs (for example "read one JSON file in the app data folder").
2. Find the narrowest permission for it in the plugin's permission list (in `src-tauri/gen/schemas/` after a build, or
   the plugin docs). Prefer a single `allow-<command>` permission to a plugin's `default` set.
3. Add it to a capability file for the named window, with a scope:

       { "identifier": "fs:allow-read-text-file", "allow": [{ "path": "$APPDATA/settings.json" }] }

4. Do not widen an existing capability's windows. If another window needs it, add a second capability.
5. Run the check: `node scripts/check-capabilities.mjs src-tauri`. It fails on wildcard windows with sensitive
   permissions, unscoped fs or http permissions, shell execute or spawn, remote URLs with commands, and a missing or
   null CSP. Fix every finding, or explain to the human why it is needed and get approval.
6. Run the app and use the feature once. Report the permissions added and why each is needed.
Skill file skills/tauri-permissions/scripts/check-capabilities.mjs Flags wide or unscoped grants and a missing CSP. 48 lines
Download Raw
#!/usr/bin/env node
// Least-privilege check for Tauri 2 capabilities. Usage: node check-capabilities.mjs <src-tauri dir>
// Exit 1 with one line per finding; exit 0 and "ok" when clean. Reads JSON capability files and tauri.conf.json only.
import fs from "node:fs";
import path from "node:path";

const root = process.argv[2] ?? "src-tauri";
const findings = [];
const SENSITIVE = /^(fs|shell|http|process|sql|store|websocket|upload):/;
const NEEDS_SCOPE = /^(fs|http):/;
const SHELL_EXEC = /^shell:(allow-execute|allow-spawn|allow-stdin-write|default)$/;

const readJson = (p) => {
  try { return JSON.parse(fs.readFileSync(p, "utf8")); } catch (e) { findings.push(`${p}: not valid JSON (${e.message})`); return null; }
};

const conf = readJson(path.join(root, "tauri.conf.json"));
const inline = conf?.app?.security?.capabilities?.filter((c) => typeof c === "object") ?? [];
if (conf && !conf.app?.security?.csp) findings.push("tauri.conf.json: app.security.csp is missing or null; keep a Content Security Policy");

const capDir = path.join(root, "capabilities");
const files = fs.existsSync(capDir) ? fs.readdirSync(capDir).filter((f) => f.endsWith(".json")) : [];
const caps = [
  ...files.map((f) => ({ where: `capabilities/${f}`, cap: readJson(path.join(capDir, f)) })),
  ...inline.map((c, i) => ({ where: `tauri.conf.json capability #${i + 1}`, cap: c })),
].filter((x) => x.cap);

for (const { where, cap } of caps) {
  const perms = (cap.permissions ?? []).map((p) => (typeof p === "string" ? { identifier: p } : p));
  const wildcard = (cap.windows ?? []).includes("*") || (cap.webviews ?? []).includes("*");
  for (const p of perms) {
    const id = p.identifier ?? "";
    if (wildcard && SENSITIVE.test(id)) findings.push(`${where}: ${id} granted to every window ("*"); name the windows`);
    if (SHELL_EXEC.test(id)) findings.push(`${where}: ${id} lets the frontend run programs; use shell:allow-open or the opener plugin`);
    const scoped = (p.allow ?? []).length > 0;
    const isScopeOnly = /:scope/.test(id);
    if (NEEDS_SCOPE.test(id) && !scoped && !isScopeOnly) findings.push(`${where}: ${id} has no "allow" scope; limit it to the paths or URLs you need`);
  }
  if (cap.remote?.urls?.length && perms.length) findings.push(`${where}: remote URLs ${cap.remote.urls.join(", ")} get ${perms.length} permission(s); needs explicit approval`);
}

if (findings.length) {
  for (const f of findings) console.log(`finding: ${f}`);
  console.log(`${findings.length} finding(s) in ${caps.length} capability set(s)`);
  process.exit(1);
}
console.log(`ok: ${caps.length} capability set(s), least privilege`);

All files: source zip · Licence MIT · By Agent Loadout · First listed

Credits

Public work that inspired this loadout. The wording here is our own; follow the links for the originals.

Installing and testing

How do I install Tauri 2 desktop app, least privilege in Claude Code?

From your project root, put AGENTS.md, CLAUDE.md, skills/tauri-permissions/SKILL.md at .claude/skills/tauri-permissions/SKILL.md, skills/tauri-permissions/scripts/check-capabilities.mjs at .claude/skills/tauri-permissions/scripts/check-capabilities.mjs. The "Claude Code" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/tauri-desktop-app/claude-code.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Tauri 2 desktop app, least privilege in Codex CLI?

From your project root, put AGENTS.md, skills/tauri-permissions/SKILL.md at .agents/skills/tauri-permissions/SKILL.md, skills/tauri-permissions/scripts/check-capabilities.mjs at .agents/skills/tauri-permissions/scripts/check-capabilities.mjs. The "Codex CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/tauri-desktop-app/codex.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Tauri 2 desktop app, least privilege in Cursor?

From your project root, put AGENTS.md, skills/tauri-permissions/SKILL.md at .agents/skills/tauri-permissions/SKILL.md, skills/tauri-permissions/scripts/check-capabilities.mjs at .agents/skills/tauri-permissions/scripts/check-capabilities.mjs. The "Cursor" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/tauri-desktop-app/cursor.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Tauri 2 desktop app, least privilege in Gemini CLI?

From your project root, put AGENTS.md, GEMINI.md, skills/tauri-permissions/SKILL.md at .agents/skills/tauri-permissions/SKILL.md, skills/tauri-permissions/scripts/check-capabilities.mjs at .agents/skills/tauri-permissions/scripts/check-capabilities.mjs. The "Gemini CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/tauri-desktop-app/gemini-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Tauri 2 desktop app, least privilege in Antigravity CLI?

From your project root, put AGENTS.md, skills/tauri-permissions/SKILL.md at .agents/skills/tauri-permissions/SKILL.md, skills/tauri-permissions/scripts/check-capabilities.mjs at .agents/skills/tauri-permissions/scripts/check-capabilities.mjs. The "Antigravity CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/tauri-desktop-app/antigravity-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Tauri 2 desktop app, least privilege in GitHub Copilot?

From your project root, put AGENTS.md, skills/tauri-permissions/SKILL.md at .agents/skills/tauri-permissions/SKILL.md, skills/tauri-permissions/scripts/check-capabilities.mjs at .agents/skills/tauri-permissions/scripts/check-capabilities.mjs. The "GitHub Copilot" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/tauri-desktop-app/copilot.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

Has Tauri 2 desktop app, least privilege been tested?

It passed the Level 1 automated install checks on 2026-10-17: the files parse, install to each agent's documented paths, and pass the safety scan. No AI agent has run it yet, so no agent pass or fail is claimed.

More for Claude Code, Codex, Cursor, Gemini CLI, Antigravity CLI and GitHub Copilot.