This document describes the security architecture of the Prompt Optimizer application, with emphasis on Cross-Origin Resource Sharing (CORS) challenges and their solutions across different deployment platforms. It covers authentication mechanisms, data privacy model, and platform-specific security considerations.
For information about deployment configuration, see Environment Configuration and API Keys. For platform-specific implementations, see Platform Implementations.
Prompt Optimizer implements a client-side security architecture where all sensitive operations occur within the user's environment. The application never routes API keys or user prompts through intermediate servers.
Security Principles:
| Principle | Implementation |
|---|---|
| Zero Server Transit | API keys and prompts never pass through application servers |
| Client-Side Storage | All configuration and history stored locally (IndexedDB or file system) |
| Direct API Communication | Browser/desktop app communicates directly with AI providers |
| No Telemetry | No analytics or tracking beyond optional Vercel Analytics |
Sources: README.md51-52 README.md79
Cross-Origin Resource Sharing (CORS) is the primary security challenge for browser-based deployments. Modern browsers enforce the Same-Origin Policy, which blocks requests from a web application to a different domain unless explicitly allowed by the target server.
CORS Failure Scenarios:
| Scenario | Root Cause | Error Type |
|---|---|---|
| Local Ollama Connection | Default CORS policy blocks browser origins | Access-Control-Allow-Origin missing |
| Commercial APIs | Vendors don't enable browser CORS (security policy) | CORS preflight rejection |
| Mixed Content | HTTPS site → HTTP localhost blocked by browser | Mixed content violation |
Sources: README.md355-357 README.md381-383
When the web application is served over HTTPS (e.g., online version, Vercel deployment), browsers enforce Mixed Content restrictions:
This security policy prevents HTTPS pages from making requests to HTTP endpoints, even if CORS is properly configured on the target server.
Sources: README.md381-389
| Deployment Platform | CORS Constraint | Solution Mechanism |
|---|---|---|
| Desktop Application | None | Native app bypasses browser security |
| Chrome Extension | Partial | Extended permissions in manifest |
| Docker (HTTP) | Same-protocol only | HTTP app → HTTP APIs allowed |
| Vercel/Online (HTTPS) | Full browser restrictions | Cannot connect to HTTP services |
The desktop application using Electron provides the most robust solution to CORS challenges through a three-tier architecture with strict security boundaries.
Electron Architecture with Code Entities
CORS Bypass Mechanisms:
| Capability | Implementation | Code Location |
|---|---|---|
| No CORS Enforcement | Core services run in Node.js main process, bypass browser security | packages/desktop/main.js528-649 |
| HTTP/HTTPS Mixed Content | Native app allows both protocols | Core adapters use Node.js fetch |
| Local Service Access | Direct socket connections to localhost services | packages/core/src/services/llm/ |
| File System Access | FileStorageProvider writes to userData | packages/desktop/main.js589-594 |
Desktop app automatically detects and uses system proxy configuration for outbound requests:
Implementation at packages/desktop/main.js190-276:
session.defaultSession.resolveProxy()undici.setGlobalDispatcher() for SDK requestsSources: packages/desktop/main.js190-276 packages/desktop/main.js528-649 README.md102-106
Docker deployments can serve the application over HTTP, allowing same-protocol communication with local HTTP services.
Configuration for Local Ollama:
Sources: README.md359-364 README.md385-388
The Chrome extension has intermediate CORS capabilities through browser extension APIs.
Manifest Permissions:
Extensions can request broad host permissions that bypass some CORS restrictions, though they still cannot violate Mixed Content policies from HTTPS extension pages.
Sources: README.md107-109
For web deployments requiring access to CORS-restricted APIs, users can deploy an API proxy service.
Proxy Configuration:
Sources: README.md373-378
Electron enforces context isolation to prevent the renderer process from accessing privileged Node.js APIs. The preload.js script acts as the security boundary.
Security Boundary Diagram
Sources: packages/desktop/preload.js1-10 packages/desktop/main.js25
The preload script at packages/desktop/preload.js implements strict IPC exposure:
IPC Handler Pattern
Key Security Patterns:
| Pattern | Implementation | Purpose |
|---|---|---|
| Explicit API Surface | contextBridge.exposeInMainWorld('electronAPI', {...}) | Only explicitly exposed APIs accessible |
| No Direct Node.js | Renderer cannot require() Node modules | Prevent arbitrary code execution |
| IPC Serialization | safeSerialize() at packages/desktop/preload.js23-36 | Strip Vue reactivity, prevent object injection |
| Response Validation | createIpcError() at packages/desktop/preload.js43-78 | Structured error handling across IPC boundary |
| Timeout Protection | withTimeout() at packages/desktop/preload.js23-36 | Prevent hanging IPC calls |
WebPreferences Configuration at packages/desktop/main.js409-413:
Exposed API Structure at packages/desktop/preload.js88-239:
electronAPI.llm.* - LLM service methodselectronAPI.model.* - Model manager methodselectronAPI.template.* - Template manager methodselectronAPI.history.* - History manager methodselectronAPI.preference.* - Preference service methodselectronAPI.image.* - Image service methodselectronAPI.context.* - Context repository methodselectronAPI.favorite.* - Favorite manager methodselectronAPI.data.* - Data export/import methodsEach method validates input, invokes IPC, and handles errors consistently.
Sources: packages/desktop/preload.js1-239 packages/desktop/main.js405-414
Vercel deployments can enable password protection through the ACCESS_PASSWORD environment variable in Vercel project settings.
Configuration:
ACCESS_PASSWORD=your_secure_passwordSources: README.md90-91 vercel.json24-31
Docker deployments implement HTTP Basic Authentication via nginx, with special handling for the MCP endpoint.
Authentication Script: docker/generate-auth.sh1-46
The script executes during container startup:
Check Password Configuration docker/generate-auth.sh4-14
Generate htpasswd File docker/generate-auth.sh22-25
Create Nginx Configuration docker/generate-auth.sh31-35
Nginx Location Blocks in docker/nginx.conf:
| Location | Auth Requirement | Purpose |
|---|---|---|
/ | auth_basic (if enabled) | Web application access |
/mcp | auth_basic off | MCP protocol endpoint (bypasses auth) |
MCP Authentication Bypass:
The MCP endpoint explicitly disables authentication because:
Configuration: Docker container exposes port 80 with nginx routing /mcp to internal port 3000.
Environment Variables:
| Variable | Default | Purpose |
|---|---|---|
ACCESS_USERNAME | admin | Basic auth username |
ACCESS_PASSWORD | (none) | Basic auth password (required to enable) |
NGINX_PORT | 80 | Internal nginx listening port |
Docker Compose Configuration: docker-compose.yml39-42
Security Considerations:
Authorization header (base64 encoded, not encrypted)127.0.0.1 for localhost-only accessRecommended Production Setup:
With HTTPS reverse proxy handling TLS termination.
Sources: docker/generate-auth.sh1-46 docker-compose.yml39-42 README.md120-126 docs/user/mcp-server.md169-183
All user data persists locally without server synchronization. Storage backends implement the IStorageProvider interface.
Storage Implementation by Platform
Storage Format by Data Type:
| Data Type | Browser Storage | Desktop Storage | Encryption |
|---|---|---|---|
| API Keys | IndexedDB via DexieStorageProvider | models.json in userData | None (OS-level protection) |
| Prompt History | IndexedDB collection | history.json | None |
| Templates | IndexedDB collection | templates.json | None |
| Preferences | IndexedDB collection | preferences.json | None |
| Context Data | IndexedDB collection | contexts.json | None |
Storage Paths (Desktop):
%APPDATA%/prompt-optimizer/ (resolved via app.getPath('userData'))~/Library/Application Support/prompt-optimizer/~/.config/prompt-optimizer/Implementation: packages/desktop/main.js589-594
Backup and Recovery (Desktop):
FileStorageProvider implements automatic backups:
<dataType>.json<dataType>.json.backupData Isolation:
Each deployment platform maintains independent storage:
chrome.storage.local APIStorage Information API (Desktop Only):
Desktop app exposes storage metadata via packages/desktop/preload.js786-793:
Used by DataManager.vue to display storage usage: packages/ui/src/components/DataManager.vue300-324
Sources: README.md79 packages/desktop/main.js589-594 packages/desktop/preload.js786-793 packages/ui/src/components/DataManager.vue14-52
API keys are stored in plaintext in local storage. Security relies on platform-specific protections and the zero-server-transit architecture.
Security Model:
Configuration Hierarchy and Key Flow:
Configuration Priority: User-modified config in storage > Environment variables
Key resolution flow:
getDefaultTextModels() reads environment variables at packages/core/src/services/model/defaults.ts40-96ModelManager persists configs to storageLLMService retrieves keys from ModelManager at request timeEnvironment Variable Scanning:
Desktop and Docker deployments support dynamic custom model detection:
VITE_CUSTOM_API_KEY_<suffix>, VITE_CUSTOM_API_BASE_URL_<suffix>, VITE_CUSTOM_API_MODEL_<suffix>CUSTOM_API_PATTERN, SUFFIX_PATTERN from @prompt-optimizer/coreRuntime Injection (Desktop):
Electron main process builds runtime_config object injected into renderer:
buildRuntimeConfigScriptFromEnv() at packages/desktop/main.js355-378VITE_* environment variables as window.runtime_configVITE_OPENAI_API_KEY and OPENAI_API_KEYSources: README.md248-289 packages/core/src/services/model/defaults.ts1-119 packages/desktop/main.js355-378 packages/desktop/main.js555-578
CORS Limitations:
| Constraint | Impact | Mitigation |
|---|---|---|
| HTTPS → HTTP blocked | Cannot access local Ollama | Use desktop app or Docker (HTTP) |
| Strict CORS policies | Commercial APIs may block browser requests | Use API proxy or desktop app |
| Public API only | Limited to CORS-enabled cloud services | Configure Custom API with proxy |
Security Recommendations:
ACCESS_PASSWORD in Vercel environment variablesVercel Configuration: vercel.json24-31
Sources: README.md379-382 vercel.json1-33
Security Checklist:
ACCESS_PASSWORD with 16+ characters-p 127.0.0.1:8081:80 (not 0.0.0.0)docker pull linshen/prompt-optimizer:latestSecure Docker Compose Configuration:
Reverse Proxy Example (nginx with TLS):
Sources: docker-compose.yml1-44 README.md112-156
Security Profile:
| Aspect | Status | Notes |
|---|---|---|
| System Access | Full Node.js privileges | Runs in Electron main process |
| CORS | Bypassed completely | Direct Node.js HTTP requests |
| File System | Full read/write | userData directory permissions |
| Code Signing | Unsigned (macOS/Windows) | Source code is auditable (AGPL-3.0) |
| Auto-Updates | Enabled via electron-updater | Update files from GitHub Releases |
macOS Gatekeeper Bypass:
Apple's Gatekeeper blocks unsigned applications. Manual bypass required:
Windows SmartScreen:
Windows Defender SmartScreen may show warning for unsigned .exe. Users must click "More info" → "Run anyway".
Update Verification:
Auto-updater downloads from GitHub Releases:
User Data Security:
Sources: README.md393-407 packages/desktop/main.js589-594 packages/desktop/config/update-config.js1-70
For users requiring access to CORS-restricted APIs from web deployments, self-hosted API proxies provide a secure intermediary.
Proxy Architecture:
Recommended Proxy Solutions:
| Proxy Tool | Features | Deployment |
|---|---|---|
| OneAPI | Multi-provider aggregation, key management, rate limiting | Docker, binary |
| NewAPI | OneAPI fork with additional providers | Docker, Vercel |
| litellm-proxy | Universal LLM gateway, load balancing | Docker, pip |
Configuration in Prompt Optimizer:
Access-Control-Allow-Origin: *https://proxy.example.com/v1)Security Trade-offs:
Sources: README.md373-378
The Model Context Protocol server exposes prompt optimization capabilities via HTTP API, with deliberate authentication bypass for protocol compatibility.
MCP Server Architecture and Network Flow
Authentication Bypass Rationale:
The MCP endpoint explicitly disables Basic Authentication (while web UI remains protected):
| Reason | Explanation |
|---|---|
| Protocol Incompatibility | MCP protocol specification does not support HTTP Basic Auth |
| Client Limitations | Claude Desktop cannot send Authorization headers to MCP servers |
| Local-Only Design | MCP intended for localhost usage, protected by network binding |
| Inspector Testing | MCP Inspector tool cannot authenticate, requires open endpoint |
Nginx Configuration for /mcp Location:
Security Model:
| Layer | Security Mechanism | Implementation |
|---|---|---|
| Network Isolation | Bind to localhost only | docker run -p 127.0.0.1:8081:80 |
| API Key Protection | Keys in environment variables, never exposed | docker-compose.yml23-29 |
| Direct API Calls | MCP server uses same core adapters as desktop | packages/mcp-server/src/config/models.ts1-69 |
| No User Data Storage | MCP server is stateless | Uses in-memory core services |
Configuration: docker-compose.yml31-36
Model Selection:
MCP server reuses @prompt-optimizer/core model system:
setupDefaultModel() at packages/mcp-server/src/config/models.ts12-66defaultModels from coreMCP_DEFAULT_MODEL_PROVIDER or first enabled modelcustom_<suffix>Exposure Recommendations:
| Deployment | Recommended Configuration |
|---|---|
| Development | Expose 3000 directly, no authentication |
| Docker (Internal) | Bind to 127.0.0.1:8081, MCP via /mcp |
| Docker (Public) | Use VPN or SSH tunnel, do not expose 8081 publicly |
| Claude Desktop | Connect to http://localhost:8081/mcp |
Known Issue (Fixed in v1.4.0+):
Earlier versions required MCP endpoint authentication workaround. Now properly configured with auth_basic off in nginx.
Sources: README.md183-245 docker-compose.yml31-36 packages/mcp-server/src/config/models.ts1-69 docs/user/mcp-server.md169-183 docs/user/mcp-server_en.md188-202
Summary: Prompt Optimizer's security architecture prioritizes client-side data processing and direct API communication. CORS challenges are addressed through platform-specific solutions, with the desktop application providing the most unrestricted access. Authentication is optional and deployment-dependent, using standard HTTP mechanisms.
Refresh this wiki