# Security Considerations When Building Tauri Apps: A Defense-in-Depth Guide

> Build secure Tauri apps with our defense-in-depth guide. Learn about layered security, CSP, capability whitelisting, and secure auto-updates. Protect your WebView and native bridge.

- Repository: [Tauri/tauri](https://github.com/tauri-apps/tauri)
- Tags: best-practices
- Published: 2026-02-26

---

**Tauri implements a layered security model that protects the WebView, native bridge, and update pipeline through compile-time CSP injection, numeric RPC identifiers, capability whitelisting, and mandatory cryptographic signatures for auto-updates.**

Understanding the security considerations when building Tauri apps is essential for shipping production-ready desktop software that resists XSS, prototype pollution, and supply-chain attacks. The `tauri-apps/tauri` repository enforces these safeguards through core crates including `tauri-utils`, `tauri`, and `tauri-runtime-wry`, with most protections configured declaratively in the [`tauri.conf.json`](https://github.com/tauri-apps/tauri/blob/main/tauri.conf.json) security section.

## Content Security Policy (CSP) Configuration

Tauri automatically injects **Content-Security-Policy** headers into every HTML asset at compile time to mitigate cross-site scripting vulnerabilities.

### Automatic Nonce and Hash Injection

The framework hardens CSP headers by automatically generating **nonce** and **hash** sources, preventing injected scripts from executing even if an attacker can manipulate the DOM. This injection logic lives in [`tauri-utils/src/html.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri-utils/src/html.rs) (lines 60-66), where the `inject_csp` function processes the HTML document and inserts the policy meta-tag.

### Customizing CSP in tauri.conf.json

Configure the `csp` field for production builds and `devCsp` for development environments. If you must disable the automatic nonce and hash injection (which opens XSS vectors), set `dangerous_disable_asset_csp_modification` to `true` as documented in [`tauri-utils/src/config.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri-utils/src/config.rs) (lines 99-108).

## RPC Security with Numeric Call IDs

Each frontend-to-backend invoke uses **numeric callback IDs** and error IDs transported via custom HTTP headers (`TAURI-Callback` and `TAURI-Error`). The parsing code in [`tauri/src/ipc/protocol.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri/src/ipc/protocol.rs) (lines 5-10) strictly validates that these values are numeric, rejecting non-numeric inputs to prevent header injection attacks. This security hardening was introduced in the 2021 release (see [`packages/api/CHANGELOG.md`](https://github.com/tauri-apps/tauri/blob/main/packages/api/CHANGELOG.md), line 968).

## Capability Whitelisting

Tauri follows the principle of least privilege through explicit **capability whitelisting**. The `capabilities` array in [`tauri.conf.json`](https://github.com/tauri-apps/tauri/blob/main/tauri.conf.json) enumerates exactly which native APIs (such as `core:window:allow-start-dragging`) are exposed to JavaScript. By default, capabilities defined under `./capabilities/` are included, but you should explicitly list only required permissions. Configuration parsing is handled in [`tauri-utils/src/config.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri-utils/src/config.rs) (lines 18-24).

## Prototype Pollution Protection

Setting `freezePrototype: true` in your security configuration makes `Object.prototype` immutable, blocking **prototype pollution** attacks on the custom protocol. This field is defined in [`tauri-utils/src/config.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri-utils/src/config.rs) (lines 95-98) and prevents attackers from manipulating the prototype chain to execute arbitrary code.

## Isolation Pattern for WebView Sandboxing

The **Isolation pattern** serves frontend assets inside an iframe with a restricted `tauri://localhost` origin, significantly reducing the attack surface of the main WebView. Configure this pattern in [`tauri.conf.json`](https://github.com/tauri-apps/tauri/blob/main/tauri.conf.json) using:

```json
{
  "pattern": {
    "use": "isolation",
    "options": { "dir": "src-tauri/isolated" }
  }
}

```

The pattern enum is defined in [`tauri-utils/src/config.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri-utils/src/config.rs) (lines 76-84).

## Updater Signature Verification

For production builds, Tauri requires a **base64-encoded public key** (`pubkey`) in [`tauri.conf.json`](https://github.com/tauri-apps/tauri/blob/main/tauri.conf.json) to cryptographically verify update authenticity. The [`tauri-cli/src/helpers/updater_signature.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri-cli/src/helpers/updater_signature.rs) module validates that downloaded updates are signed with the corresponding private key before installation, preventing supply-chain attacks where malicious actors might distribute compromised binaries.

## Hardened Security Configuration Example

The following [`tauri.conf.json`](https://github.com/tauri-apps/tauri/blob/main/tauri.conf.json) implements all critical security features:

```json
{
  "tauri": {
    "security": {
      "csp": "default-src 'self'; script-src 'self' 'nonce-{nonce}'; style-src 'self' 'nonce-{nonce}'",
      "devCsp": "default-src 'self' http: https: data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'",
      "freezePrototype": true,
      "dangerousDisableAssetCspModification": false,
      "capabilities": [
        "core:window:allow-close",
        {
          "identifier": "drag-window",
          "permissions": ["core:window:allow-start-dragging"]
        }
      ],
      "pubkey": "YOUR_BASE64_PUBKEY"
    },
    "pattern": {
      "use": "isolation",
      "options": { "dir": "src-tauri/isolated" }
    }
  }
}

```

All fields are optional except `pubkey` for production updater builds.

## Programmatic CSP Injection

While rarely necessary, you can manually inject CSP headers using the `tauri-utils` crate:

```rust
use tauri::utils::html::{inject_csp, parse};

fn add_custom_csp(html: &str) -> String {
    let doc = parse(html);
    let csp = "default-src 'self'; script-src 'self' 'nonce-abc123'";
    inject_csp(&doc, csp);
    doc.to_string()
}

```

The `inject_csp` function is implemented in [`tauri-utils/src/html.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri-utils/src/html.rs).

## Update Signing Workflow

To implement cryptographic update verification:

```bash

# Generate a signing key pair (run once)

tauri signer generate-keypair

# Sign your update artifact (produces .sig file)

tauri signer sign --private-key ./my_key

# Store the public key in tauri.conf.json under security.pubkey

```

The signing implementation resides in [`tauri-cli/src/helpers/updater_signature.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri-cli/src/helpers/updater_signature.rs).

## Summary

- **CSP headers** are automatically injected with nonces and hashes via [`tauri-utils/src/html.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri-utils/src/html.rs) to prevent XSS.
- **Numeric RPC IDs** in [`tauri/src/ipc/protocol.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri/src/ipc/protocol.rs) prevent header injection attacks by validating callback identifiers.
- **Capability whitelisting** restricts JavaScript access to native APIs through explicit [`tauri.conf.json`](https://github.com/tauri-apps/tauri/blob/main/tauri.conf.json) configuration.
- **Prototype freezing** blocks pollution attacks by making `Object.prototype` immutable.
- **Isolation pattern** sandboxes frontend code in a restricted iframe origin.
- **Updater signatures** require a `pubkey` in [`tauri.conf.json`](https://github.com/tauri-apps/tauri/blob/main/tauri.conf.json) and verification logic in [`updater_signature.rs`](https://github.com/tauri-apps/tauri/blob/main/updater_signature.rs) to prevent supply-chain compromises.

## Frequently Asked Questions

### How do I report a security vulnerability in Tauri?

Do not open public issues or pull requests. Instead, follow the private vulnerability disclosure process documented in [`SECURITY.md`](https://github.com/tauri-apps/tauri/blob/main/SECURITY.md) at the repository root to ensure vulnerabilities are patched before public disclosure.

### What is the most critical security setting for production Tauri apps?

The `pubkey` configuration for the updater is mandatory for production builds, as it prevents supply-chain attacks by ensuring only cryptographically signed updates signed with your private key can be installed on user machines.

### Can I disable Tauri's automatic CSP modifications?

Yes, using the `dangerous_disable_asset_csp_modification` flag in [`tauri.conf.json`](https://github.com/tauri-apps/tauri/blob/main/tauri.conf.json), but this is strongly discouraged as documented in [`tauri-utils/src/config.rs`](https://github.com/tauri-apps/tauri/blob/main/tauri-utils/src/config.rs) because it removes the automatic nonce and hash injection that protects against XSS vectors.

### How does Tauri prevent prototype pollution attacks?

By setting `freezePrototype: true` in the security configuration, Tauri makes `Object.prototype` immutable, preventing attackers from injecting properties into the prototype chain that could be exploited through the custom protocol handler.