Security
Tusab runs locally on the user's machine — a privacy advantage, but that doesn't eliminate risk. Three attack surfaces exist even in a local desktop app: the FastAPI API on localhost:8001, user input (URLs, uploads, pasted text), and the React interface running inside Electron.
What was already secure from the start
- Electron with best practices —
contextIsolation: true,nodeIntegration: false,sandbox: true, explicit preload script - Safe subprocesses — yt-dlp is always executed via an argument list, never
shell=True(prevents shell injection) - Sensitive files in
.gitignore—credentials.json,token.json,.env,agent_config.jsonhave never been committed - File name sanitization — regex strips special characters before saving uploads to disk
Audit and fixes applied
Two rounds of end-to-end code auditing (June 2026) covered subprocess injection, path traversal, input validation, Electron security, secret storage, CORS, XSS, and dependencies. Twelve findings identified and fixed:
| # | Fix | Severity |
|---|---|---|
| 1 | CORS restricted to localhost:8001 (was: allow_origins=["*"]) | Critical |
| 2 | yt-dlp playlist ID validated by regex before composing commands | Critical |
| 3 | Upload limited to 50 MB before processing | High |
| 4 | File delete protected against path traversal (os.path.realpath()) | High |
| 5 | dangerouslySetInnerHTML eliminated from React | Medium |
| 6 | API keys migrated to the OS keychain via safeStorage | Medium |
| 7 | Size limits on every Pydantic field (max_length) | Low |
| 8 | Path traversal in the static file server fixed | High |
| 9 | Prompt injection mitigated with XML delimiters in the RAG prompt | Medium |
| 10 | Google Drive query injection fixed with quote escaping | Medium |
| 11 | YouTube URL validated against a regex whitelist | Low |
| 12 | Chat history moved to the server — client payload ignored | Low |
Example — CORS
Before: allow_origins=["*"], allow_credentials=True — any site open in the user's browser, or any local process, could make unrestricted requests to the API.
After: allow_origins=["http://localhost:8001", "http://127.0.0.1:8001"], allow_credentials=False — only the app itself can call the API.
Example — prompt injection in the RAG pipeline
The prompt assembles each component with semantic XML delimiters:
<source id="1">
<title>...</title>
<date>...</date>
<link>...</link>
<content>...</content>
</source>
<conversation_history>...</conversation_history>
<question>...</question>
The model receives an explicit structure: content inside <source> is treated as reference data, not as instruction. The question is capped at 2,000 characters.
Two additional layers were added in a later audit (September 2026):
- Explicit anti-injection instruction: the system message instructs the model to treat any text inside
<content>that looks like a command ("ignore previous instructions", "reveal your configuration") as part of the content to be reported — never as an order to follow. - Post-response detection: a heuristic checks whether the generated answer contains the textual signature of having complied with an injected command (e.g., mentions of having switched persona or revealed configuration). When detected, the interface shows a warning — the answer is not blocked or replaced, just flagged for review.
Both layers are surface-level reinforcement, not guaranteed isolation: no LLM treats delimiters as a real sandbox. The structural defense (the architecture never injects secrets into the prompt) remains the primary protection against sensitive data exfiltration.
Example — path traversal on delete
real_path = os.path.realpath(txt_path)
real_subdir = os.path.realpath(subdir)
if not real_path.startswith(real_subdir + os.sep):
return {"error": True, "message": "Invalid path"}
os.path.realpath() resolves the real absolute path — including any ../ or symlink — and verifies it's actually inside the allowed folder before any delete operation.
General posture
- No central server to attack or compromise
- Data never leaves the machine without explicit consent
- Electron configured with isolation best practices
- The 12 fixes close the realistic attack surfaces for the current distribution phase
What's still missing for an enterprise posture: local authentication token for the API (server mode), pinned dependency versions, automated tests covering critical security endpoints.
For personal data handling (LGPD/GDPR), see Privacy.