# Security Considerations for Storing Meeting Data in Meetily's Local SQLite Database

> Secure your sensitive meeting data in Meetily's local SQLite database. Learn about file permissions, encryption, SQL injection, and secure deletion to protect transcripts and metadata.

- Repository: [Zackriya Solutions/meetily](https://github.com/Zackriya-Solutions/meetily)
- Tags: best-practices
- Published: 2026-08-02

---

**Meetily stores meeting transcripts and metadata in a local SQLite database located in the user's AppData directory, requiring careful attention to file permissions, encryption at rest, SQL injection prevention, and secure deletion practices to protect sensitive conversation data.**

The open-source meeting assistant Meetily (Zackriya-Solutions/meetily) persists sensitive conversation data—including transcripts, summaries, and meeting metadata—using a local SQLite database accessed through Tauri's SQL plugin. Because this data resides unencrypted on the user's filesystem by default, understanding the security implications of the storage architecture is critical for developers deploying the application in privacy-sensitive environments.

## File System Permissions and Storage Location

Meetily registers its SQLite database using the Tauri SQL plugin with a specific base directory configuration that determines where the database file physically resides on disk.

In [`frontend/src-tauri/src/lib.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/lib.rs) (lines 10–11), the plugin is initialized as follows:

```rust
.plugin(tauri_plugin_sql::Builder::default()
    .add_plugin("sqlite", tauri::api::path::BaseDirectory::AppData)

```

This configuration stores the database file in the operating system's per-user application data directory ( `%APPDATA%` on Windows, `~/Library/Application Support/` on macOS, or `~/.local/share/` on Linux). While this location is user-specific and generally inaccessible to other user accounts on the same machine, the file permissions depend on the parent directory's umask or ACL settings.

**Security implication:** If the file is created with overly permissive modes (e.g., world-readable `0644`), any process running on the same system could potentially read meeting transcripts. The application should ensure the database file is created with restrictive permissions (mode `0600` on Unix systems) to prevent unauthorized access from other users or sandbox-escaped applications.

## Data-at-Rest Encryption

The project's [`Cargo.toml`](https://github.com/Zackriya-Solutions/meetily/blob/main/Cargo.toml) (line 13) declares `rusqlite = "0.28"` as a dependency, indicating the underlying SQLite access layer. However, the current implementation stores data in a standard SQLite file without encryption.

**Security implication:** Without encryption, meeting data is vulnerable to:
- Extraction from stolen or lost devices
- Exposure through filesystem backups or cloud synchronization services (OneDrive, iCloud, Dropbox) that sync the AppData folder
- Forensic recovery from unallocated disk space after deletion

To mitigate these risks, Meetily should implement **SQLCipher** (an encrypted SQLite variant) or apply application-level encryption to sensitive fields before database insertion. Developers can replace the standard `rusqlite` dependency with `rusqlite` bundled with SQLCipher support, or encrypt specific columns (like transcript content) using AES-256-GCM before storing them via the Tauri SQL plugin.

## SQL Injection and Query Safety

The Tauri commands exposed to the frontend serve as the interface between the JavaScript application layer and the Rust database backend. In [`frontend/src-tauri/src/api/commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/api/commands.rs) (lines 3–12), placeholder implementations demonstrate the intended query patterns:

```rust
#[tauri::command]
async fn list_meetings() -> Result<Vec<String>, String> {
    // Placeholder: query SQLite database for meetings
    Ok(vec!["Demo Meeting".to_string()])
}

#[tauri::command]
async fn add_meeting(name: String) -> Result<(), String> {
    // Placeholder: insert into SQLite DB
    Ok(())
}

```

**Security implication:** As these commands evolve from placeholders to production code, they must use **prepared statements** or parameterized queries rather than string concatenation. The `rusqlite` crate provides the `prepare` method and `params!` macro to safely handle user input. Direct string interpolation of the `name` parameter into SQL statements would create SQL injection vulnerabilities, allowing malicious meeting titles to alter database structure or extract unauthorized data.

## Isolation and Attack Surface Minimization

The frontend invokes these database operations through Tauri's IPC bridge, as seen in [`frontend/src/app/page.tsx`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src/app/page.tsx) (lines 9–11):

```typescript
invoke("list_meetings").then((data) => {
  console.log("Meetings:", data);
});

```

**Security consideration:** Only explicitly registered Tauri commands are exposed to the webview. The current implementation exposes `list_meetings` and `add_meeting`, which limits the attack surface compared to raw SQL access. Developers should maintain this principle of least privilege by:
- Avoiding generic SQL execution commands that accept raw query strings from the frontend
- Validating all inputs at the Rust boundary before database interaction
- Implementing command-level authorization checks if multi-user scenarios are introduced

## Backup and Cloud Synchronization Leakage

Modern operating systems increasingly synchronize application data directories to cloud storage services. Because Meetily stores its SQLite file in `BaseDirectory::AppData`, users with cloud backup enabled may inadvertently upload unencrypted meeting transcripts to third-party servers.

**Mitigation strategies:**
- Document the database location clearly so privacy-conscious users can exclude the directory from synchronization
- Implement encryption-at-rest so that even if the file is synced, the contents remain inaccessible without the decryption key
- Provide in-app warnings when sensitive meetings are detected, advising users about cloud backup implications

## Secure Deletion and Data Remnance

When meetings are deleted through the `add_meeting` or future delete commands, standard SQLite `DELETE` operations do not immediately overwrite the underlying data pages. The content may remain recoverable through forensic analysis of the database file until the space is reused by subsequent operations.

**Security best practice:** When implementing deletion functionality, the application should:
- Execute `VACUUM` after sensitive deletions to compact the database and overwrite freed pages
- Alternatively, use encrypted databases where key rotation or deletion renders old pages unrecoverable without the corresponding keys

## Summary

- **Storage location:** Meetily stores data in the user's AppData directory via `tauri::api::path::BaseDirectory::AppData` (lib.rs lines 10–11), which is user-specific but potentially vulnerable to permission misconfigurations.
- **Encryption status:** The database currently uses standard SQLite via `rusqlite` (Cargo.toml line 13) without encryption, exposing data to filesystem-level attacks and backup leakage.
- **Query safety:** Future implementations of commands like `list_meetings` and `add_meeting` (commands.rs lines 3–12) must use parameterized statements to prevent SQL injection.
- **IPC exposure:** The Tauri command bridge (invoked from page.tsx lines 9–11) should remain minimal and avoid exposing raw SQL execution capabilities to the frontend.
- **Data lifecycle:** Secure deletion requires explicit `VACUUM` operations or encryption to prevent forensic recovery of deleted meeting content.

## Frequently Asked Questions

### Is Meetily's SQLite database encrypted by default?

No, according to the source code analysis of Zackriya-Solutions/meetily, the database uses standard SQLite through the `rusqlite` crate (version 0.28) without SQLCipher or field-level encryption. Meeting transcripts and metadata are stored as plaintext in the AppData directory, making them readable by any process with appropriate filesystem access or through cloud backup synchronization.

### Where exactly does Meetily store the local database file?

The database is configured in [`frontend/src-tauri/src/lib.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/lib.rs) to use `tauri::api::path::BaseDirectory::AppData`, which resolves to `%APPDATA%\meetily` on Windows, `~/Library/Application Support/meetily` on macOS, or `~/.local/share/meetily` on Linux. The exact filename is determined by the Tauri SQL plugin's initialization parameters.

### How can developers prevent SQL injection in Meetily's database commands?

Developers should implement the placeholder commands in [`frontend/src-tauri/src/api/commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/api/commands.rs) using `rusqlite`'s prepared statement API rather than string concatenation. Instead of building SQL strings with user input, use `connection.prepare("INSERT INTO meetings (name) VALUES (?1)")` and bind parameters using `params![name]` to ensure malicious input cannot alter query structure.

### What happens to meeting data when a user deletes a meeting in Meetily?

Standard SQLite deletion marks rows as free space but does not immediately overwrite the underlying data, meaning deleted meeting transcripts may remain recoverable through forensic tools until the database pages are reused. To ensure secure deletion, the application should execute the `VACUUM` command after deletions, or better yet, implement an encrypted database where deletion involves removing the encryption key or rotating keys to render old data permanently inaccessible.