Skip to content

security

Douwe de Vries edited this page Jul 1, 2026 · 1 revision

Security

CSV Anonymizer is a local-first desktop app. Its standard detection, preview, transformation, and reporting paths run locally through Rust code in crates/csv-anonymizer-core. Optional Smart replacement uses the user's local Ollama runtime through src-tauri/src/local_ai.

Active contributors: Douwe de Vries

Local-first boundary

The default workflow reads a local CSV or pasted sample, detects likely sensitive fields, previews replacements, and writes transformed output. It does not call hosted PII APIs.

Important boundaries:

  • Rust detection and transformation run in crates/csv-anonymizer-core.
  • Tauri commands in src-tauri/src/commands expose local desktop operations to frontend/src/tauri.ts.
  • Smart replacement sends selected values only to the configured loopback Ollama endpoint, currently http://127.0.0.1:11434 in src-tauri/src/local_ai/mod.rs.
  • Model weights and Ollama runtime binaries are not bundled with the app or tracked in the repository.
  • Output is transformed source data, not a formal anonymity or differential privacy guarantee.

File path grants

PathAccess in src-tauri/src/path_access.rs keeps in-memory grants for input and output paths:

  • Input files are canonicalized and must exist as regular files.
  • Output paths are normalized by canonicalizing the parent directory.
  • Existing output leaves must be regular files.
  • Existing output symlinks are rejected.
  • Existing output leaves that resolve outside the output directory are rejected.

src-tauri/src/commands/shared.rs asks for explicit Tauri dialog confirmation when a typed path has not already been granted through Browse.

Output safety

Output safety is split across Tauri and core code:

  • src-tauri/src/commands/shared.rs rejects output suffixes with path separators or control characters before constructing suggested output paths.
  • crates/csv-anonymizer-core/src/file_ops.rs writes through a temporary file and renames into place on success.
  • crates/csv-anonymizer-core/src/csv_io.rs rejects ragged rows with non-empty fields beyond the header shape.
  • crates/csv-anonymizer-core/src/csv_io.rs preserves blank rows and normalizes short rows to the header length.

These guards protect against accidental writes outside the selected location, unsafe symlink leaves, and partial output after transformation errors.

CSV formula neutralization

Spreadsheet formula injection is handled in crates/csv-anonymizer-core/src/csv_io.rs. Every output record is passed through neutralize_spreadsheet_formula before writing. Values that begin with formula prefixes, leading whitespace before formula prefixes, tabs, returns, newlines, or full-width formula variants are prefixed with a single quote.

This applies to headers and data cells because the writer path uses write_csv_output_record for both.

Tauri CSP and capabilities

src-tauri/tauri.conf.json defines a restrictive content security policy:

  • default-src 'self'
  • scripts from self only
  • object embedding disabled
  • base URI restricted to self
  • frame ancestors disabled
  • local IPC connect sources only

Development CSP allows the Vite dev server at http://localhost:5173 and WebSocket HMR.

src-tauri/capabilities/default.json is the command allowlist for the main window. It lists each allow-* command permission, core:default, core:app:allow-set-app-theme, and dialog open/save permissions.

Smart replacement validation

Smart replacement is optional and off by default in settings. The Local AI path is deliberately constrained:

  • src-tauri/src/local_ai/ollama.rs checks Ollama /api/version and /api/tags.
  • src-tauri/src/local_ai/provider.rs posts to http://127.0.0.1:11434/api/generate.
  • src-tauri/src/local_ai/prompt.rs asks for JSON matching a schema with original and replacement pairs.
  • crates/csv-anonymizer-core/src/smart.rs validates responses before storing replacements.

Rejected Smart replacement outputs include unexpected originals, missing outputs, empty outputs, same-as-original outputs, outputs containing the original value, control characters, duplicate originals, and duplicate outputs. Missing or unsafe model output falls back through normal Smart replacement error and fallback handling rather than silently accepting unsafe replacements.

CI secrets and release material

Release signing inputs are GitHub Actions secrets or variables used by .github/workflows/release.yml. The repository should contain only secret names and release logic, never secret values.

scripts/check-release-metadata.mjs rejects tracked Local AI model/runtime artifacts such as .gguf files, model caches, Ollama caches, and llama-server binaries. This keeps local model setup as an in-app or Ollama action rather than a bundled repository artifact.

Related pages: Deployment, Tauri commands, Configuration, and Patterns and conventions.

Clone this wiki locally