Security
The trust boundary
VeloxKit has a clear trust boundary between JavaScript and Rust:
βββββββββββββββββββββββββββββββ
β JavaScript (your app code) β β untrusted user input lives here
β React, business logic β
βββββββββββββββββββββββββββββββ€ β capability-gated bridge
β Rust (native runtime) β β trusted, validated
β File system, SQLite, AI β
βββββββββββββββββββββββββββββββThe Rust layer validates all inputs from JavaScript before executing native operations. SQL parameters are always parameterized β the db API does not support raw SQL interpolation from user input.
JS vs Rust: decision tree
Keep in JavaScript:
- Business logic, UI state, data transformation
- Anything that benefits from React reactivity
- Non-sensitive computation
Move to Rust (native extensions) if:
- You need to process large files (>10MB) without blocking the UI thread
- You need cryptographic operations beyond what JS provides
- You need to interface with C libraries directly
- Performance-critical loops that run thousands of times per second
See Native Extensions for how to write Rust extensions.
SQL injection prevention
Always use parameterized queries. Never interpolate user input into SQL:
// β Safe β parameterized
const results = db.query('SELECT * FROM notes WHERE title LIKE ?', [`%${userInput}%`])
// β Unsafe β never do this
const results = db.query(`SELECT * FROM notes WHERE title LIKE '%${userInput}%'`)The second form will throw a lint error in VeloxKit's ESLint plugin (eslint-plugin-veloxkit).
Storing secrets
Use the OS keychain via the credentials capability β never store secrets in plain files or db:
import { credentials } from 'veloxkit'
// Store
await credentials.set('my-app', 'api-key', secretValue)
// Retrieve
const key = await credentials.get('my-app', 'api-key')
// Delete
await credentials.delete('my-app', 'api-key')This uses Keychain on macOS, Credential Manager on Windows, and libsecret on Linux.
Network security
All network.fetch calls use TLS by default. To allow plain HTTP in development:
// veloxkit.config.ts
dev: {
allowInsecureHttp: true, // development only, ignored in production builds
}Never store API keys, passwords, or tokens in veloxkit.config.ts, source code, or the SQLite database. Use credentials (OS keychain) for all secrets.
Content from untrusted sources
If your app renders content fetched from remote sources (user-generated content, markdown, etc.):
- Do not use
dangerouslySetInnerHTMLor equivalent - Sanitize before rendering with a library like
dompurify(adapted for VeloxKit's renderer) - VeloxKit's
Textcomponent does not interpret HTML β it is safe to pass raw strings
Code signing and notarization
For public distribution:
- macOS: notarize with
veloxkit notarize. Requires an Apple Developer account and theidentifierfield in config. - Windows: sign with
veloxkit sign --cert path/to/cert.pfx. Unsigned apps show SmartScreen warnings. - Linux: not required but AppImage signing is supported.
See Packaging for complete instructions.