본문으로 건너뛰기
cccskills
무료GitHub에 공개

desktop-security-tauri

Tauri 2.x deny-by-default security model, capabilities, permissions, scopes, ACL

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(5)

  • SKILL.md14.8 KB
  • examples/core.md13.9 KB
  • examples/custom-permissions.md6.7 KB
  • metadata.yaml748 B
  • reference.md11.2 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Tauri Capabilities & ACL

Quick Guide: Tauri 2 uses a deny-by-default security model. Nothing is accessible unless explicitly granted in a capability file (src-tauri/capabilities/*.json). Capabilities bind permissions to specific windows. Permissions follow the plugin:command identifier pattern. Scopes restrict operations to specific paths or URLs with allow/deny lists (deny always wins). Every plugin and custom command needs a permission grant -- missing permissions cause runtime errors, not compile errors.

Current version: Tauri 2.x (stable). Tauri 1.x used a boolean allowlist which is completely removed in v2.


<critical_requirements>

CRITICAL: Before Using This Skill

(You MUST create at least one capability file in src-tauri/capabilities/ -- without it, ALL plugin and core API calls fail at runtime)

(You MUST include core:default in every capability -- without it, basic app lifecycle commands fail)

(You MUST scope permissions to specific windows using the windows array -- a window not listed in any capability has zero IPC access)

(You MUST use deny scopes to restrict sensitive paths -- deny ALWAYS takes precedence over allow)

(You MUST use plugin:permission-name format for plugin permissions and plain permission-name for app commands)

</critical_requirements>


Auto-detection: Tauri capabilities, src-tauri/capabilities, capability file, permissions, ACL, allow-scope, deny-scope, core:default, fs:allow, shell:allow, http:allow, permission set, remote domain, CapabilityRemote, desktop-schema.json, mobile-schema.json, scope allow deny, Tauri security, tauri permission denied, capability identifier

When to use:

  • Creating or modifying capability files for a Tauri 2 app
  • Granting permissions to specific windows or webviews
  • Restricting filesystem, HTTP, or shell access with scoped permissions
  • Writing custom permissions for your own Tauri commands
  • Grouping permissions into permission sets
  • Enabling remote domain access to Tauri APIs
  • Debugging "permission denied" or "not allowed" runtime errors
  • Migrating from the Tauri v1 allowlist to v2 capabilities

When NOT to use:

  • Writing Tauri commands or IPC bridge logic (use desktop-framework-tauri)
  • Plugin installation and registration (use desktop-framework-tauri)
  • Window management, system tray, or menus (use desktop-framework-tauri)
  • General Rust programming unrelated to Tauri ACL
  • Frontend framework patterns

Key patterns covered:

Detailed resources:

  • examples/core.md - Capability files, scoped permissions, window/platform targeting, remote access, debugging
  • examples/custom-permissions.md - Custom permission definitions, permission sets, app-level permissions
  • reference.md - Permission identifier patterns, path variables, core permissions, v1 migration checklist

<philosophy>

Philosophy

Tauri 2 implements a deny-by-default access control model. Every potentially dangerous operation (filesystem, network, shell, clipboard) is blocked until explicitly granted in a capability file. This is a fundamental shift from v1's boolean allowlist -- instead of toggling features on/off globally, you define granular permissions scoped to specific windows, platforms, and paths.

The security hierarchy:

  1. Capabilities - Bind permissions to windows/webviews. A window not listed in any capability has zero IPC access.
  2. Permissions - Define what operations are allowed or denied. Follow the plugin:command identifier pattern.
  3. Scopes - Restrict WHERE operations can act (paths, URLs). Deny always supersedes allow.

Key design decisions:

  • Granular, not global -- permissions are per-window, per-platform, per-path
  • Deny wins -- if a path is denied by any scope, it is blocked even if allowed by another
  • Runtime, not compile-time -- missing permissions cause runtime errors, not build errors. This makes debugging harder but allows dynamic permission resolution.
  • Schema-driven -- capability files reference auto-generated schemas (desktop-schema.json, mobile-schema.json) for IDE autocompletion

When to invest in fine-grained capabilities:

  • Multi-window apps where windows need different permission levels
  • Apps handling sensitive data (credentials, financial records)
  • Apps distributed publicly where security posture matters
  • Apps with remote content that needs limited API access

When simple capabilities suffice:

  • Single-window apps with straightforward needs
  • Internal tools where the security boundary is less critical
  • Prototypes and MVPs where iteration speed matters more
</philosophy>
<patterns>

Core Patterns

Pattern 1: Capability File Structure

Every Tauri 2 app needs at least one capability file in src-tauri/capabilities/. The file grants permissions to specific windows.

{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "main-capability",
  "description": "Permissions for the main application window",
  "windows": ["main"],
  "permissions": ["core:default", "event:default", "window:default"]
}

Key fields: identifier (unique name), windows (which windows get these permissions), permissions (what operations are allowed). The $schema field enables IDE autocompletion for available permissions.

Key rule: All capabilities in src-tauri/capabilities/ are auto-enabled unless you explicitly list capabilities in tauri.conf.json's app.security.capabilities array -- in which case only the listed ones are used.

See examples/core.md for all capability fields and patterns.


Pattern 2: Scoped Permissions (Allow/Deny)

Restrict plugin operations to specific paths using inline scope objects. Deny always takes precedence.

{
  "identifier": "fs:allow-read-text-file",
  "allow": [{ "path": "$APPDATA/**" }]
}
{
  "identifier": "fs:deny-read-text-file",
  "deny": [{ "path": "$APPDATA/secrets/**" }]
}

Key rule: Deny always supersedes allow. If a path matches both an allow and a deny scope, it is blocked. Use $APPDATA, $HOME, $RESOURCE and other Tauri path variables -- not hardcoded OS paths.

See examples/core.md for filesystem, HTTP, and shell scope patterns.


Pattern 3: Window-Specific Capabilities

Different windows get different permission sets. An editor window gets write access; a viewer window gets read-only access.

{
  "identifier": "editor-capability",
  "windows": ["editor"],
  "permissions": ["core:default", "fs:allow-write-text-file"]
}
{
  "identifier": "viewer-capability",
  "windows": ["viewer"],
  "permissions": ["core:default", "fs:allow-read-text-file"]
}

Key rule: A window not listed in any capability's windows array has zero IPC access. Windows listed in multiple capabilities get the merged permissions of all matching capabilities.

See examples/core.md for multi-window and wildcard patterns.


Pattern 4: Platform-Specific Capabilities

Use the platforms field to restrict capabilities to specific operating systems.

{
  "identifier": "desktop-features",
  "windows": ["main"],
  "platforms": ["linux", "macOS", "windows"],
  "permissions": ["core:default", "shell:allow-open", "global-shortcut:default"]
}

Key rule: Platform values are "linux", "macOS", "windows", "iOS", "android". Splitting by platform prevents permission errors for platform-specific plugins.

See examples/core.md for mobile-specific capability examples.


Pattern 5: Custom Permission Definitions

Define permissions for your own Tauri commands using TOML files in src-tauri/permissions/.

# src-tauri/permissions/default.toml
[default]
description = "Default app permissions"
permissions = ["allow-greet", "allow-get-settings"]
# src-tauri/permissions/admin.toml
[[permission]]
identifier = "allow-admin-ops"
description = "Allow admin operations"
commands.allow = ["reset_database", "export_all_data"]

Key point: Tauri auto-generates allow-* and deny-* permissions for every command registered in generate_handler![]. Custom permission files let you group them and add scopes.

See examples/custom-permissions.md for permission sets and custom scope definitions.


Pattern 6: Remote Domain Access

Grant remote web content access to Tauri APIs using the remote field with URL patterns.

{
  "identifier": "remote-api-access",
  "windows": ["main"],
  "remote": {
    "urls": ["https://*.mydomain.dev"]
  },
  "permissions": ["core:default", "notification:default"]
}

Key rule: Remote URLs gain access to the specified Tauri APIs -- understand the security implications. On Linux and Android, Tauri cannot distinguish between iframe requests and window requests, so remote access should be used cautiously on those platforms.

See examples/core.md for remote access patterns and security considerations.

</patterns>

<decision_framework>

Decision Framework

What Permissions Does My App Need?

What does the app do?
|-- Reads/writes files?
|   +-- tauri-plugin-fs permissions with path scopes
|-- Makes HTTP requests from Rust backend?
|   +-- tauri-plugin-http permissions with URL scopes
|-- Opens file/folder dialogs?
|   +-- tauri-plugin-dialog permissions
|-- Runs external processes?
|   +-- tauri-plugin-shell permissions (desktop only)
|-- Shows system notifications?
|   +-- tauri-plugin-notification permissions
|-- Uses persistent key-value storage?
|   +-- tauri-plugin-store permissions
+-- Basic app + window lifecycle only?
    +-- core:default is sufficient

How Granular Should Capabilities Be?

How many windows does the app have?
|-- Single window?
|   +-- One capability file with all permissions is fine
|-- Multiple windows with SAME needs?
|   +-- One capability file listing all windows in the array
+-- Multiple windows with DIFFERENT needs?
    +-- Separate capability files per window (principle of least privilege)

Does the app need platform-specific features?
|-- Same features on all platforms?
|   +-- Omit the platforms field
+-- Different features per platform?
    +-- Separate capability files with platforms field

Where to Put the Scope?

Is the scope for a built-in plugin?
|-- YES -> Inline in the capability file permissions array
|           { "identifier": "fs:allow-read-text-file", "allow": [...] }
+-- NO -> Is it for your custom commands?
    |-- YES -> Define in src-tauri/permissions/*.toml
    +-- NO -> It might not need a scope -- simple allow/deny suffices

</decision_framework>


<red_flags>

RED FLAGS

High Priority Issues:

  • Missing core:default in a capability -- basic app lifecycle commands fail silently
  • No capability file at all in src-tauri/capabilities/ -- ALL IPC calls fail at runtime
  • Using v1 tauri.allowlist in config -- completely removed in v2, does nothing
  • Granting fs:allow-read-text-file without path scope -- allows reading ANY file on the system
  • Missing windows array in capability -- permissions apply to no windows (useless capability)

Medium Priority Issues:

  • Using wildcard "windows": ["*"] in production -- every window gets these permissions, including dynamic ones
  • Not splitting capabilities by platform -- desktop-only plugins (shell, autostart, global-shortcut) cause errors on mobile
  • Overly broad HTTP scopes (http:allow-fetch without URL scope) -- allows requests to any URL
  • Granting write permissions when only read is needed -- violates least privilege

Common Mistakes:

  • Forgetting that deny always wins -- adding a deny scope and wondering why the allow scope "doesn't work"
  • Using OS paths (/home/user/) instead of Tauri path variables ($HOME/) in scopes
  • Expecting compile-time errors for missing permissions -- they are runtime errors only
  • Using app.security.capabilities in tauri.conf.json to list some capabilities, then wondering why unlisted capability files are ignored (explicit list overrides auto-discovery)
  • Capability identifier containing digits after first character (identifiers are restricted to [a-z] plus hyphens)

Gotchas & Edge Cases:

  • Stale ACL in builds: If you add a new permission but the build does not regenerate, the old ACL is embedded. Clean build (cargo clean) or ensure build.rs has cargo:rerun-if-changed for the capabilities directory
  • Schema path: The $schema field must point to the correct generated schema (../gen/schemas/desktop-schema.json or mobile-schema.json). Run cargo tauri dev once to generate schemas
  • Merged capabilities: A window listed in multiple capabilities gets ALL permissions from ALL matching capabilities merged together -- there is no "override" mechanism
  • Remote access on Linux/Android: Tauri cannot distinguish iframe requests from window requests on these platforms, making remote domain restrictions less effective
  • Permission identifier format: Plugin permissions use plugin:permission-name, app-defined permissions use just permission-name (no prefix). Using the wrong format causes "permission not found" errors
  • TOML vs JSON for permissions: Capability files accept JSON or TOML. Custom permission definitions (in src-tauri/permissions/) must be TOML only

</red_flags>


<critical_reminders>

CRITICAL REMINDERS

(You MUST create at least one capability file in src-tauri/capabilities/ -- without it, ALL plugin and core API calls fail at runtime)

(You MUST include core:default in every capability -- without it, basic app lifecycle commands fail)

(You MUST scope permissions to specific windows using the windows array -- a window not listed in any capability has zero IPC access)

(You MUST use deny scopes to restrict sensitive paths -- deny ALWAYS takes precedence over allow)

(You MUST use plugin:permission-name format for plugin permissions and plain permission-name for app commands)

Failure to follow these rules will cause silent runtime permission denials that do not surface at compile time.

</critical_reminders>

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

agents-inc/skills252026년 10월 17일 업데이트

agents-inc의 스킬 모두 보기

이 스킬의 문제 신고