Skip to content

Security

The ElyOS application system runs applications in a sandboxed environment. The system performs static code analysis on uploaded applications and rejects those containing forbidden patterns.


The following code patterns are not permitted for security reasons:

PatternWhy it’s forbidden
eval()Executes arbitrary code
new Function(...)Executes arbitrary code
innerHTML =XSS attack vector
outerHTML =XSS attack vector
document.write()DOM manipulation, XSS
dangerouslySetInnerHTMLReact-style XSS
fetch() to external domainData exfiltration
XMLHttpRequest to external domainData exfiltration
import() from external URLLoading arbitrary code
Accessing another plugin’s schemaViolates data isolation
Accessing platform.* schemaAccessing system data
Accessing auth.* schemaAccessing authentication data
// ❌ FORBIDDEN
eval('console.log("hello")');
new Function('return 1 + 1')();
element.innerHTML = userInput;
document.write('<script>...</script>');
fetch('https://external-api.com/data');
import('https://cdn.example.com/lib.js');
// ✅ ALLOWED
console.log('hello');
const result = 1 + 1;
element.textContent = userInput; // textContent is safe
window.webOS.remote.call('myFunction'); // via SDK

Only whitelisted packages may be specified in the dependencies field of manifest.json. The plugin upload will fail if other dependencies are included.

PackageVersion
svelte^5.x.x
lucide-svelte^0.x.x
@elyos/*any version
// manifest.json — allowed
{
"dependencies": {
"svelte": "^5.0.0",
"lucide-svelte": "^0.263.1",
"@elyos/my-package": "^1.0.0"
}
}
// manifest.json — FORBIDDEN (upload will fail)
{
"dependencies": {
"axios": "^1.0.0",
"lodash": "^4.17.0"
}
}

A plugin can only access the SDK functions for which it has requested permission in manifest.json. The system checks permissions at runtime.

PermissionDescriptionAffected SDK functions
databaseRead/write to the plugin’s own schemadata.set(), data.get(), data.delete(), data.query(), data.transaction()
notificationsSend notifications to usersnotifications.send()
remote_functionsCall server-side functionsremote.call()
file_accessFile upload/download(planned)
user_dataRead user profile data(planned)
manifest.json
{
"permissions": [
"database",
"notifications",
"remote_functions"
]
}

Each plugin gets its own database schema: plugin_{plugin_id}. The schema is only created if the "database" permission is listed in the plugin’s manifest.json — if the plugin doesn’t use a database, no schema is created.

The plugin can only perform database operations within this schema.

// ✅ Own schema — allowed
const rows = await window.webOS.data.query(
'SELECT * FROM my_table WHERE user_id = $1',
[userId]
);
// The system automatically runs this in the plugin_{id} schema
// ❌ Other schema — FORBIDDEN, throws an error
const rows = await window.webOS.data.query(
'SELECT * FROM platform.users'
);

If the plugin needs its own tables, you can place SQL files in the migrations/ folder. Details: SDK — Data Service.


Error Handling from a Security Perspective

Section titled “Error Handling from a Security Perspective”
try {
const result = await window.webOS.remote.call('sensitiveFunction');
} catch (error) {
// Error types:
// PERMISSION_DENIED — missing permission
// PLUGIN_INACTIVE — plugin is not activated
// REMOTE_CALL_TIMEOUT — timeout
// ✅ User-friendly error message
window.webOS.ui.toast('Operation failed', 'error');
// ❌ Do not display the raw error message to the user
// window.webOS.ui.toast(error.message, 'error');
}

  • Validate user input before writing to the database
  • Use parameterized queries ($1, $2, …) to prevent SQL injection
  • Do not store sensitive data (passwords, tokens) in the plugin database
  • Do not trust client-side validation — also validate in server functions
  • Follow the principle of least privilege (only request what you actually use)