new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Tauri · Develop · all subjects

security patterns

45 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Brownfield pattern is the default

The Brownfield pattern is the default security pattern in Tauri. It is designed to be the simplest and most straightforward pattern, attempting to maintain compatibility with existing frontend projects and requiring nothing additional to what an existing web frontend might use inside a browser.

Brownfield pattern configuration

To explicitly set the Brownfield pattern in Tauri, add the following configuration to tauri.conf.json: set app > security > pattern > use to "brownfield". There are no additional configuration options for the brownfield pattern.

Brownfield pattern browser compatibility

The Brownfield pattern in Tauri aims to be compatible with existing browser applications, but not everything that works in existing browser applications will work out-of-the-box in Tauri.

Message passing safety compared to shared memory

Message passing is safer than shared memory or direct function access because the recipient is free to reject or discard requests. For example, if the Tauri Core process determines a request to be malicious, it can simply discard it and never execute the corresponding function.

Commands do not share FFI security pitfalls

Although Commands provide a foreign function interface-like abstraction, they do not share the same security pitfalls as real FFI interfaces because they still use message passing under the hood.

Isolation pattern purpose and threat model

The Isolation pattern intercepts and modifies Tauri API messages sent by the frontend before they reach Tauri Core using injected JavaScript. Its purpose is to protect applications from unwanted or malicious frontend calls to Tauri Core, particularly against Development Threats from many nested dependencies in frontend build tools and bundled dependencies.

Isolation pattern recommendation

Tauri highly recommends using the Isolation pattern whenever it can be used. Because it intercepts all messages from the frontend, it can always be used. Tauri strongly suggests locking down applications whenever using external Tauri APIs by utilizing the Isolation application to verify IPC inputs are within expected parameters.

Isolation pattern implementation with iframes

The Isolation pattern injects a secure application between the frontend and Tauri Core using the sandboxing feature of iframes. Tauri enforces routing of all IPC calls through the sandboxed Isolation application first. After the Isolation application processes the message, it is encrypted using the browser's SubtleCrypto implementation with AES-GCM and a runtime-generated key, then passed back to the frontend for delivery to Tauri Core where it is decrypted.

IPC message flow with Isolation pattern

The approximate steps of an IPC message with the Isolation pattern are: 1) Tauri's IPC handler receives a message, 2) IPC handler passes to Isolation application, 3) Isolation application hook runs in sandbox and potentially modifies the message, 4) Message is encrypted with AES-GCM using a runtime-generated key in sandbox, 5) Encrypted message passes from Isolation application to IPC handler, 6) Encrypted message passes from IPC handler to Tauri Core.

Isolation pattern key generation

New cryptographic keys are generated each time the Tauri application is run to prevent someone from manually reading keys for a specific version and using them to modify encrypted messages.

Isolation pattern performance considerations

The Isolation pattern adds encryption overhead compared to the Brownfield pattern. However, most applications should not notice runtime costs of encrypting/decrypting IPC messages as they are relatively small and AES-GCM is relatively fast. Performance-sensitive applications with carefully-maintained small dependency sets may be more affected. Key generation overhead is not generally noticeable if the system has adequate entropy, though headless environments for integration testing may benefit from entropy-generating services like haveged.

Isolation pattern limitation on Windows

External files do not load correctly inside sandboxed iframes on Windows due to platform inconsistencies. To work around this, Tauri inlines scripts at build time, taking the content of scripts relative to the Isolation application and injecting them inline. Typical bundling and simple script inclusion work, but newer mechanisms such as ES Modules will not successfully load.

Isolation application recommendation to keep simple

The Isolation application should be kept as simple as possible to protect against Development Threats. Dependencies should be kept minimal and required build steps should be minimized to avoid needing to worry about supply chain attacks against the Isolation application on top of frontend attacks.

Isolation pattern hook implementation

The Isolation application uses a global hook function `window.__TAURI_ISOLATION_HOOK__` that receives incoming IPC payloads. This function can inspect, modify, or reject the payload before it is encrypted and passed to Tauri Core. The hook must return the payload to be processed.

Isolation pattern configuration example

To enable the Isolation pattern in tauri.conf.json, set the security.pattern.use field to 'isolation' and provide the directory path in security.pattern.options.dir. Example configuration: {"app": {"security": {"pattern": {"use": "isolation", "options": {"dir": "../dist-isolation"}}}}}

Isolation application file structure

The Isolation application consists of an HTML file that includes a JavaScript file. The HTML file should include a script tag that loads the JavaScript file (e.g., `<script src="index.js"></script>`). The JavaScript file defines the `window.__TAURI_ISOLATION_HOOK__` function that intercepts IPC messages.

Principle of Least Privilege in Tauri

You can limit the blast radius of potential exploits by handing out only the minimum amount of permissions to each process, just enough so they can get their job done. This pattern is known as the Principle of Least Privilege. The less access you give a process, the less harm it can do if it gets compromised.

Security best practices for WebView processes

Security best practices apply to Tauri applications: you must always sanitize user input, never handle secrets in the Frontend, and ideally defer as much business logic as possible to the Core process to keep your attack surface small.

Command permissions are denied by default

By default, plugin commands are not accessible by the frontend and will return a denied error rejection. Commands must have permissions defined to be executable.

Permission files location and format

Permissions are defined as JSON or TOML files inside the `permissions` directory. Each file can define a list of permissions, permission sets, and the plugin's default permission.

Permission structure in TOML

Permissions are defined with an `identifier` (unique name), `description` (human-readable explanation), and `commands` object. The `commands` object contains `allow` array (list of allowed commands) and `deny` array (list of denied commands). Example: `identifier = "allow-start-server"`, `description = "Enables the start_server command."`, `commands.allow = ["start_server"]`.

Command scope for plugin permissions

Command scopes allow plugins to define deeper restrictions for individual commands. Plugin consumers define scopes for specific commands in their capability files. Access command-specific scope in Rust using the `tauri::ipc::CommandScope` struct with generic type parameter for the scope data type. Methods include `allows()` and `denies()`.

Global scope for plugins without command restrictions

When a permission defines no commands to allow or deny, it is a scope permission that defines only a global scope for the plugin. Access global scope in Rust using `tauri::ipc::GlobalScope` struct with generic type parameter for the scope data type. Methods include `allows()` and `denies()`. Recommendation: check both global and command scopes for flexibility.

Scope entry schema generation with schemars

Scope entries require the `schemars` dependency to generate a JSON schema so plugin consumers know the scope format. Add `schemars = "0.8"` to both `dependencies` and `build-dependencies` in Cargo.toml since the scope module is shared between app code and build script. In build.rs, use `tauri_plugin::Builder::new(COMMANDS).global_scope_schema(schemars::schema_for!(scope::Entry)).build()`.

Permission sets for command groups

Permission sets are groups of individual permissions that provide higher-level abstraction for plugin management. Use them when a single API uses multiple commands or when there's logical connection between commands. Defined with `identifier` (unique name), `description` (explanation), and `permissions` array listing the included permission identifiers.

Default permission with identifier 'default'

The default permission is a special permission set with identifier `default`. It is recommended to enable required commands by default. Defined in a permission file with `description` and `permissions` array listing default-enabled permissions.

Autogenerated permissions in build.rs

Define a `COMMANDS` const array in build.rs listing command names in snake_case (matching the function name). Tauri automatically generates `allow-$commandname` and `deny-$commandname` permissions for each command. Example: `const COMMANDS: &[&str] = &["upload"];` generates `allow-upload` and `deny-upload` permissions. Call `tauri_plugin::Builder::new(COMMANDS).build()` in build.rs.

Android permissions in TauriPlugin annotation

Android permissions are defined in the @TauriPlugin annotation with a permissions array. Each permission entry includes the permission string and an alias. Example: ```kotlin @TauriPlugin( permissions = [ Permission(strings = [Manifest.permission.POST_NOTIFICATIONS], alias = "postNotification") ] ) class ExamplePlugin(private val activity: Activity): Plugin(activity) { } ```

iOS permission methods checkPermissions and requestPermissions

iOS plugins should override the checkPermissions and requestPermissions methods to manage permissions. Example: ```swift class ExamplePlugin: Plugin { @objc open func checkPermissions(_ invoke: Invoke) { invoke.resolve(["postNotification": "prompt"]) } @objc public override func requestPermissions(_ invoke: Invoke) { // request permissions here // then resolve the request invoke.resolve(["postNotification": "granted"]) } } ```

Tauri automatically implements checkPermissions and requestPermissions commands

Tauri automatically implements checkPermissions and requestPermissions commands for plugins. These commands can be called directly from JavaScript or Rust using the plugin command naming convention.

Plugin event capability requirement

Listening to plugin events from JavaScript is gated by the capability and permission system. Add the plugin's permission (commonly <plugin-name>:default or a specific allow-listen-* permission) to the permissions array of a capability under src-tauri/capabilities/. Example: ```json { "identifier": "default", "windows": ["main"], "permissions": ["<plugin-name>:default"] } ```

Built-in Tauri dev server security limitations

The built-in Tauri development server does not support mutual authentication or encryption. It should never be used for development on untrusted networks due to these security limitations.

Grant sidecar execute/spawn permissions in capabilities

To run a sidecar from JavaScript, grant permission in src-tauri/capabilities/default.json by adding a permission entry with identifier 'shell:allow-execute' (for execute() method) or 'shell:allow-spawn' (for spawn() method). Include the sidecar entry in the 'allow' array with the 'name' matching a path from externalBin and 'sidecar: true' flag.

JavaScript sidecar permission configuration example

{ "permissions": [ "core:default", { "identifier": "shell:allow-execute", "allow": [ { "name": "binaries/app", "sidecar": true } ] } ] }

Define sidecar arguments in capabilities

Arguments for sidecar commands are defined in src-tauri/capabilities/default.json within the 'allow' entry for that sidecar. Arguments can be: static strings (exact values like 'arg1' or '-a'), dynamic values defined with regex validator objects (like {"validator": "\\S+"}), true (allow any arguments), or false (disable all arguments). Arguments must be passed in the exact order defined.

Sidecar argument configuration example in capabilities

{ "identifier": "shell:allow-execute", "allow": [ { "args": [ "arg1", "-a", "--arg2", { "validator": "\\S+" } ], "name": "binaries/my-sidecar", "sidecar": true } ] }

Tauri security features

Tauri is built on Rust, which provides memory, thread, and type-safety benefits that apps can automatically leverage. Tauri undergoes security audits for major and minor releases, which cover code in the Tauri organization and upstream dependencies. A Tauri security policy and audit reports are publicly available.

capabilities/ directory default location

The capabilities/ directory is the default folder where Tauri reads capability files from. Capabilities are required to allow commands to be used in JavaScript code.

Tauri security audit

The entire Tauri project has been horizontally and vertically audited by an independent third party, with the full audit report available at https://github.com/tauri-apps/tauri/blob/dev/audits/Radically_Open_Security-v1-report.pdf

Tauri local-first application design

Tauri allows you to build local-first applications without a webserver, so users do not have to share their data with external services. Using local databases and Rust-based cryptography is supported.

Tauri 1.2.0 security fix for file dialog escaping

Tauri 1.2.0 includes a security patch for a vulnerability in file dialog and drag-and-drop functionality. Incorrect escaping of special characters in paths allowed partial bypass of the fs scope definition. The vulnerability was limited to neighboring files and subfolders of already allowed paths and required user interaction (selecting a malicious file during file picker) combined with adversary-controlled logic. The patch is also available in versions 1.0.7 and 1.1.2. See advisory GHSA-q9wv-22m9-vhqh for details.

ZipSlip vulnerability fix in bundle extraction

Tauri 1.3 fixed a ZipSlip vulnerability in the bundler where remote files were extracted using ZipFile::name() instead of ZipFile::enclosed_name(). This could allow malicious archives with paths like ../../../../foo.sh to extract files outside the intended directory. The implementation was changed to use the proper extraction method.

Tauri v2.0.0-beta.0 is undergoing security audit

Tauri v2.0.0-beta.0 is currently being audited to ensure security, similar to what was done for the v1 stable release.

External security audit for Tauri 2.0

Tauri 2.0 underwent an external security audit by RadicallyOpenSecurity funded by NLNet. All findings were fixed and retested. One finding (CVE-2024-35222) was distributed as a security patch during beta. The full audit report is available in the Tauri repository at audits/Radically_Open_Security-v2-report.pdf. Users should upgrade to the release candidate to ensure all fixes are applied.

External security audit

Tauri 2.0's major changes and architecture were independently audited by Radically Open Security during the beta and release candidate period. The audit was funded by NLNet via funding from NGI. The audit report is available at https://github.com/tauri-apps/tauri/blob/dev/audits/Radically_Open_Security-v2-report.pdf. The audit results led to rewrites of the dev server exposure for mobile development, hardening of the iFrame API exposure, fixing of scope validation and resource identifier access for the fs and http plugins, and improved inter-process communication stability.

Give your agent this brain