freezr Security Model
freezr apps can be created by 3rd parties, and running third-party code on a server naturally sets off alarm bells! Here is the mechanism freezr uses to isolate different apps and allow them to run simultaneously on the same freezr.
Note: This is a technical document for developers who want to understand how freezr's security model works before trusting it with their data or code. It specifically addresses how client-side JavaScript can be run by different 3rd party apps on freezr, securely. Server-side JavaScript can only be run with server admin's permission or via bacvkground jobs (i.e. serverless instances.)
The Core Problem
When multiple applications run on the same origin (example.com), the browser's same-origin policy provides no isolation between them:
- Apps can read each other's cookies
- Apps can fetch each other's pages
- Apps can make requests using each other's credentials
- Apps share localStorage, sessionStorage, and the DOM
freezr uses path-based credential scoping combined with token-based API authentication to provide app isolation (without needing them to run on separate domains or sub domains).
Architecture Overview
Path structure
/account/home → "Account" functions (treated as an app even with trusted code, but is given access to 3rd party app data) /admin/home → "Admin" functions (treated as an app even with trusted code) /apps/com.example.todo/dashboard.html → Todo app (third-party code) /apps/com.anotherdeveloper.calendar/app.html → Calendar app (third-party code) /apps/com.bigbank.freezrbanking/accounts.html → Banking app (third-party code)
Each app gets its own path namespace. Credentials are scoped to these paths.
Note: Note: Public pages do not follow this security model - they are public, and don't even leave any coookies for unauthenticated users.
Authentication Flow for App Pages
3. API Token Validation
API endpoints validate tokens against the requested resource:
// API request structure POST /feps/write/com.example.todo.items/item_123 Authorization: Bearer <token> // Server-side validation 1. Extract token from Authorization header 2. Lookup token in cache → get userId and appName 3. Verify appName has permission to access 'com.example.todo.items' collection 4. Verify session userId matches token userId 5. Process request
Each API call validates:
- Token is valid and not expired
- Token with combination of both
appNameanduserIdhas permission to the requested resource - Token's
userIdmatches current session. (This is disabled for offline apps like mobile apps.)
4. Server-Side Rendered Data Protection
For pages with server-side data, an additional check prevents malicious fetching of the web page:
// Banking app tries to fetch Todo dashboard:
fetch('/apps/com.example.todo/dashboard')
// Request headers:
Sec-Fetch-Mode: cors // Browser-generated, cannot be forged
Sec-Fetch-Site: same-origin
Sec-Fetch-Dest: empty
// Server checks:
if (page has sensitive data && sec-fetch-mode !== 'navigate') {
return 403; // Block JavaScript fetch
}
// Legitimate navigation:
// User clicks link or types URL
Sec-Fetch-Mode: navigate // Only set by real navigation
// Server returns page with data
Sec-Fetch-Mode is a forbidden header — JavaScript cannot set or modify it. This provides cryptographic proof of legitimate navigation.
For browsers without
Sec-Fetch-Mode, freezr doesn't allow data to be injected in HTML on the server side. A nonce-based algorithm can allow this, but as major browsers are supported, this is not a priority.
Content Security Policy (CSP)
Every app page served by freezr includes a strict Content Security Policy that limits what client-side code can do.
Default CSP for App Pages
script-src 'self' 'nonce-<random>' — Only server-loaded scripts with matching nonce style-src 'self' 'unsafe-inline' — Styles from self, inline styles allowed connect-src 'self' — Fetch/XHR restricted to same origin img-src * data: — Images from any source form-action 'self' — Forms can only submit to freezr server default-src 'self' — Everything else restricted to same origin frame-src 'none' — No iframes child-src 'none' — No workers/nested browsing contexts object-src 'none' — No plugins (Flash, Java, etc.)
This means by default, third-party app code cannot:
- Execute injected inline scripts or event handlers (blocked by nonce)
- Send data to external servers (blocked by connect-src)
- Load scripts from external domains (blocked by script-src)
- Use
eval()or dynamic code generation (blocked by default) - Submit forms to external servers (blocked by form-action)
- Embed iframes (blocked by frame-src)
Permission-Based CSP Relaxation
Some apps legitimately need capabilities that the default CSP blocks. freezr handles this through its permission system — the app declares what it needs in its manifest, and the user must explicitly grant each capability:
| Permission | CSP Change | Use Case |
|---|---|---|
| external_fetch | connect-src relaxed to * |
App needs to call external APIs |
| external_scripts | script-src adds https: |
App loads JS libraries from CDNs |
| unsafe_eval | script-src adds 'unsafe-eval' |
App uses eval() or templating engines |
| allow_self_frames | frame-src relaxed to 'self' blob: |
App needs same-origin iframes (e.g. preview panes) |
Each relaxation is shown to the user with a risk warning before they grant it. Permissions can be revoked at any time.
Public Page CSP
Public pages (content shared without login) use a different, simpler CSP:
script-src 'self' 'nonce-<random>' — Scripts locked to nonce form-action 'self' — Forms restricted to freezr server object-src 'none' — No plugins
Public pages intentionally allow iframes, images, and styles from any source — this is public content that may embed external media like YouTube videos. The key protections are: no arbitrary script execution (nonce), no form submission to external sites, and no cookie exposure.
Server-Side Protections
Session Cookie
The session cookie that identifies logged-in users is configured with:
httpOnly: true— JavaScript cannot read it, even within appssameSite: 'strict'— Not sent on cross-site requestssecure: true— Only sent over HTTPS (in production)path: /(default) — Sent to all routes on the server
Since the session cookie is httpOnly, no app — malicious or otherwise — can read or exfiltrate it via JavaScript.
Public Page Cookie Protection
Public pages run middleware that intercepts and blocks any attempt by the server to set cookies on the response. The session cookie is still sent by the browser (it has path /), but since it is httpOnly, JavaScript on the public page cannot read it.
Input Validation
- App names: Validated against a strict character set — blocks
< > " / { } \and other special characters - Permission names: Must match
/^[a-zA-Z0-9._-]+$/ - Table IDs: Must match
/^[a-zA-Z0-9._-]+$/ - Public page IDs: Cannot start with reserved route prefixes (
/app,/admin,/account,/login, etc.) to prevent path confusion attacks
What Is Protected
✅ Token Theft Between Apps
Attack: Calendar app tries to steal Banking app token.
// Calendar app at /apps/calendar/
document.cookie
// Returns: "calendar_token=abc123"
// Banking token (Path=/apps/banking) not visible
fetch('/apps/banking/accounts')
// Banking token not sent (path mismatch)
// Calendar token sent instead (wrong token for banking)
Path isolation prevents token access.
✅ Unauthorized API Access
Attack: Calendar app makes API call with stolen token.
POST /feps/write/banking_accounts/account_789 Authorization: Bearer <calendar_token> // Server validation: // Token appName: 'calendar' // Requested collection: 'banking_accounts' // Permission: calendar has NO access to banking_accounts // Result: 403 Forbidden
Permission system enforces app boundaries.
✅ Server-Side Data Theft
Attack: Calendar app fetches Banking dashboard HTML.
fetch('/apps/banking/accounts')
// Sec-Fetch-Mode: cors (JavaScript fetch)
// Server sees:
// - Not a real navigation (sec-fetch-mode !== 'navigate')
// - Banking page has server-rendered sensitive data
// Result: 403 Forbidden
Sec-Fetch-Mode detection blocks malicious fetches.
✅ Cross-Site Request Forgery (CSRF)
// API calls require Authorization header (token) // Cookies alone are insufficient // External sites cannot get token value // SameSite=strict prevents cookie sending from external sites
Token-based auth prevents CSRF.
What Is NOT Protected
⚠️ XSS Within an App
freezr's CSP uses nonce-based script protection, which blocks all inline scripts — including injected <script> tags and inline event handlers. However, if the app developer's own JavaScript code has vulnerabilities (e.g., using innerHTML with unsanitised user input), an attacker could still manipulate the DOM within that app's page.
// Example: app code with innerHTML vulnerability element.innerHTML = userProvidedData; // Attacker could inject HTML that changes visible content, // creates fake UI elements, or adds misleading links. // However, injected <script> tags and event handlers // are blocked by CSP nonce enforcement.
connect-src 'self' prevents data exfiltration to external domains. All app code is open source so malicious patterns can be detected by review or automated scanning.
⚠️ Social Engineering
A malicious app could create fake UI elements that mimic login screens or other trusted interfaces.
<div style="position:fixed; top:0; left:0; width:100%;
height:100%; background:white; z-index:9999">
<h1>Your session expired. Please log in again:</h1>
<form action="/apps/malicious.app/steal">
<input type="text" name="username">
<input type="password" name="password">
<button>Login</button>
</form>
</div>
form-action 'self' prevents forms from submitting data to external domains — the form above can only post to the freezr server itself.Mitigation: User awareness (legitimate freezr login only happens at
/account/login), trusted app ecosystem and open source review.
⚠️ Browser Extensions
Malicious browser extensions can read everything on the page, including tokens. Users must be cautious about installed extensions.
⚠️ Compromised Devices
If the user's device has malware, all bets are off.
⚠️ App Identity Is Install-Time Trust
freezr verifies which installed app is calling — every API token is minted for a specific (user, app) pair, and permission grants attach to the app's name for that user. It does not verify that the code running under that name is the code the user believes it is. App identity is established at install time: whoever can install apps on an account (the user — or an attacker holding their session) can install different code under an existing app's name and inherit that name's grants.
In practice this adds little to a full account compromise (an attacker with your session can simply grant themselves new permissions). The realistic risk is update and re-install hijacking: a user refreshes an app from a URL that now serves different code, and the new code silently inherits every grant made to the old one.
⚠️ Cross-Server Sharing Trusts the Recipient's Server
When you share data with a user on another freezr server, the unit of trust is that person and their server — not the app named in the grant. Your server delivers a copy; from that point, only the recipient's server decides which of its apps can read it, and a modified or malicious server can ignore those boundaries entirely. More fundamentally, no protocol can stop a recipient from copying delivered data onward.
Attack Scenarios and Mitigations
Scenario 1: Token Reuse Attack
Attack: Attacker captures token via network sniffer, tries to reuse it.
- HTTPS required (encrypted transport)
- Short token lifetime
- Session validation (token must match active session)
- Token tied to specific user and app
Result: Attack window is small; token only works for intended app.
Scenario 2: Path Traversal
Attack: Malicious app tries to access parent path cookies.
// Banking app at /apps/com.bigbank.freezrbanking document.cookie // Tries to access tokens at /apps/ or /
Protection: Browser enforces cookie path semantics. Cookies are visible only to paths matching or beneath the cookie path. Result: Attack impossible (browser-level protection).
Scenario 3: API Permission Bypass
Attack: App modifies request to access unauthorized collection.
POST /feps/write/admin_users/user_123 Authorization: Bearer <regular_app_token>
Protection: Server validates app permissions before processing any request. Result: 403 Forbidden.
Scenario 4: Session Fixation
Attack: Attacker sets a known token in victim's browser.
- Tokens are random, not predictable
- Tokens stored server-side with validation
- Session cookie is httpOnly (cannot be set by JavaScript)
- Tokens expire quickly
Result: Attack difficult to execute, limited impact.
Scenario 5: Clickjacking
Attack: Malicious app embeds legitimate app in invisible iframe, tricks user into clicking.
frame-src 'none'andchild-src 'none'in CSP — apps cannot embed iframes by default- Apps that need iframes must request
allow_self_frames, which only allows same-origin and blob iframes
Result: Attack blocked by CSP.
Scenario 6: Supply Chain Attack
Attack: Node modules may be compromised
Protection: freezr purposefully uses as few dependencies as possible. see dependencies.
Known Limitations
1. Trust in Browser Implementation
Path-based cookie isolation depends on correct browser implementation of cookie scoping. If a browser has a bug in cookie path handling, isolation could break.
2. HttpOnly=false Requirement
Tokens must be readable by JavaScript (to send in Authorization headers). This makes them vulnerable to XSS within the app's scope.
3. Sec-Fetch-Mode Dependency
Server-side data protection relies on Sec-Fetch-Mode headers. Older browsers without support require fallback validation. .
4. User Granted Permissions
If a user grants a malicious app broad permissions, that app can access sensitive data.
- Clear UI for permission grants
- Granular permissions (specific collections, read vs write)
- Easy permission revocation
- Audit log of cross-app access
5. Insider Threats
A malicious app can abuse permissions granted by users or exploit bugs in freezr itself. An app can mount a Denial of Service attack, or use the person's login to start mining crypto.
- Open source code review
- App vetting process
- User ratings and reviews
- Rate limiting and anomaly detection
6. App Code Authenticity
Permission grants bind to an app's name (per user), not to its code. Installing different code under the same name — typically via a hijacked update or re-install source — inherits the name's existing grants. Partial mitigations under consideration (none implemented yet):
- Bundle-hash continuity — record a hash of the app files at install; surface "this app's code has changed since you granted these permissions", with re-approval required only for sensitive permission types (forcing re-grants on every update would make automated updates as cumbersome as manual ones)
- Developer signing keys (trust-on-first-use) — the manifest carries the developer's public key; updates must be signed by the same key, so same-name code from a different publisher is treated as a different app with no inherited grants
- Domain-bound app ids — app ids are already reverse-domain (com.example.app); the server could verify domain control at install (e.g. a /.well-known file or DNS record), tying the name to its real publisher
7. Cross-Server Trust Boundary
Within one server, freezr enforces which user and which app can read shared data. Across servers it cannot: the receiving server is the only party in a position to enforce anything on its side, so a cross-server grant is ultimately a grant to the (user, server) pair. App names in cross-server grants are labels the remote server may honour, not boundaries your server can enforce. Server-to-server attestation (a server signing claims about what its apps are) could raise the bar but still reduces to trusting the remote server's word.
Implementation Requirements
To maintain security guarantees, freezr implementations must:
- Enforce HTTPS — All cookies must have
Secureflag - Set proper cookie attributes —
SameSite=strict, correct path scoping - Validate on every request — Never trust client-supplied app names
- Store tokens server-side — Use cache with TTL
- Check Sec-Fetch-Mode — For pages with server-side data rendering
- Implement permission system — Default deny, explicit grants only
- Rate limit — Prevent token generation DoS
- Log security events — Token validation failures, permission violations
- Regular security updates — Stay current with browser changes
Testing Your Implementation
Test 1: Cross-App Token Access
// At /apps/app1/:
const app1Token = document.cookie.match(/app1_token=([^;]+)/)[1];
// At /apps/app2/:
const app2Cookie = document.cookie;
// Should NOT contain app1_token
fetch('/apps/app1/somepage');
// Should NOT send app1_token (path mismatch)
Test 2: API Permission Enforcement
// Get app1 token
const token = getCookie('app1_token');
// Try to access app2 data
fetch('/ceps/read/app2_data/item', {
headers: { 'Authorization': `Bearer ${token}` }
});
// Should return 403 Forbidden (no permission)
Test 3: Sec-Fetch-Mode Validation
// From /apps/app1/, try to fetch /apps/app2/ with server-side data
fetch('/apps/app2/dashboard');
// Should return 403 if dashboard has initial_queries
// (sec-fetch-mode will be 'cors', not 'navigate')
// Click a real link to /apps/app2/dashboard
// Should work (sec-fetch-mode is 'navigate')
Test 4: Token Expiration
// Get token
const token = getCookie('app_token');
// Wait 6 minutes
setTimeout(() => {
fetch('/ceps/read/data/item', {
headers: { 'Authorization': `Bearer ${token}` }
});
// Should return 401 Unauthorized (token expired)
}, 360000);
Conclusion
freezr's security model uses path-based credential scoping and token-based API authentication to isolate apps on a single domain. The approach provides strong isolation while maintaining good UX. The summary below focuses on freezr-specific issues, rather than general risks of cloud impementations and software.
- Path-scoped cookies prevent token theft between apps
- Token validation prevents unauthorized API access
- Sec-Fetch-Mode detection prevents data theft via fetch
- Permission system enables controlled cross-app access
- XSS within an app can compromise that app's data
- Social engineering attacks are possible
- Depends on correct browser implementation
- User-granted permissions can be abused
- App identity is install-time trust — grants bind to an app's name, not its code
- Cross-server sharing trusts the recipient and their server; app boundaries are not enforceable remotely
Last updated: April 2026
This document describes freezr's security model. Implementation details may vary. Always review the actual source code and conduct security audits before deploying.