{"id":98031,"date":"2026-10-07T03:02:00","date_gmt":"2026-10-07T07:02:00","guid":{"rendered":"https:\/\/overcentral.com\/en\/?p=98031"},"modified":"2026-09-29T07:56:46","modified_gmt":"2026-09-29T11:56:46","slug":"emdash-user-roles-permissions-guide-98031","status":"publish","type":"post","link":"https:\/\/overcentral.com\/en\/emdash-user-roles-permissions-guide-98031\/","title":{"rendered":"EmDash User Roles and Permissions: The Complete Guide"},"content":{"rendered":"<p>WordPress plugins have full database access by design. Install a contact form plugin with a bug, and an attacker can read your entire user table. That&#8217;s not a flaw in the plugin\u2014it&#8217;s how the architecture was built. <a href=\"https:\/\/emdash.com\" target=\"_blank\" rel=\"noopener noreferrer\" data-iacss-external=\"1\">EmDash<\/a>, Cloudflare&#8217;s spiritual successor to WordPress, fixes this with a permission model that starts at the code level. Every plugin declares exactly what it can touch. Every user role is scoped to specific actions. And authentication uses passkeys, not passwords.<\/p>\n<p>This guide breaks down how EmDash handles user roles, plugin capabilities, API permissions, and content-type access. No vague claims\u2014every point is grounded in a specific example from the platform&#8217;s design.<\/p>\n<h2>The Role-Based Access Control System<\/h2>\n<p>EmDash ships with four predefined user roles: administrator, editor, author, and contributor. Each role is limited to the actions its name implies. An administrator can install plugins, modify site settings, and manage <a href=\"https:\/\/overcentral.com\/en\/meta-muse-filesystem-96794\/\" title=\"Meta Opens Muse Filesystem to All Users\" data-iacss-internal=\"1\">all users<\/a>. An editor can publish and edit any post but cannot touch plugin configuration or user accounts. An author can write and publish their own posts only. A contributor can draft content but cannot publish.<\/p>\n<p>These roles are enforced at the API and UI level. If an editor tries to navigate to the plugin management page, the interface simply <a href=\"https:\/\/overcentral.com\/en\/rascal-does-not-dream-trailer-release-80139\/\" title=\"Rascal Does Not Dream Drops Trailer for Final Film\" data-iacss-internal=\"1\">does not<\/a> render that section. The server rejects any API call that falls outside the role&#8217;s scope. There is no way to bypass this with a direct URL or a crafted request\u2014the permission check happens before any data access.<\/p>\n<h3>How Roles Map to Actions<\/h3>\n<ul>\n<li><strong>Administrator<\/strong>: Full access to all settings, plugins, themes, content types, users, and site configuration. Can delete the entire site if they choose.<\/li>\n<li><strong>Editor<\/strong>: Can create, edit, publish, and delete any post or page. Can manage comments and categories. Cannot access plugins, themes, user management, or site-level settings.<\/li>\n<li><strong>Author<\/strong>: Can create, edit, and publish their own posts. Cannot edit others&#8217; content. Cannot access settings or plugins.<\/li>\n<li><strong>Contributor<\/strong>: Can write drafts and submit for review. Cannot publish. Cannot upload media directly.<\/li>\n<\/ul>\n<p>This is a familiar model for anyone who has used WordPress. The difference is that EmDash&#8217;s roles are enforced at the infrastructure level, not just in the UI. A compromised author account cannot escalate privileges by exploiting a plugin vulnerability, because plugins themselves are sandboxed.<\/p>\n<h2>Plugin Capabilities: How Permissions Work in Sandboxed Plugins<\/h2>\n<p>The most important permission system in EmDash is not for users\u2014it is for plugins. Every plugin runs inside its own V8 isolate, powered by Cloudflare&#8217;s dynamic workers. The plugin cannot access the database, the file system, or other plugins unless a <strong>capability manifest<\/strong> explicitly grants it.<\/p>\n<p>Here is a concrete example from EmDash&#8217;s documentation. A plugin that sends an email notification when a post is published declares these capabilities:<\/p>\n<p>&#8220;`<\/p>\n<p>definePlugin({<\/p>\n<p>  id: &#8220;email-notifier&#8221;,<\/p>\n<p>  version: &#8220;1.0.0&#8221;,<\/p>\n<p>  capabilities: [&#8220;read content&#8221;, &#8220;send email&#8221;]<\/p>\n<p>})<\/p>\n<p>&#8220;`<\/p>\n<p>That is all the plugin can do. It can read content (posts, pages, media metadata) and send emails. It cannot write to the database, delete anything, make network requests to external servers, or access user passwords. If a compromised update tries to exfiltrate data by calling an external API, the runtime physically blocks the connection because the capability manifest did not declare network access.<\/p>\n<p>In WordPress, the same plugin would have full access to <code>wpdb<\/code>codecodecode and could run arbitrary SQL queries. A bug in the email plugin could read the entire users table. In EmDash, that is architecturally impossible.<\/p>\n<h3>Dynamic Workers and the Permission Boundary<\/h3>\n<p>The sandbox is not a policy layer\u2014it is enforced by Cloudflare&#8217;s runtime. Dynamic workers run on V8 isolates, which are lightweight, hardware-isolated execution environments. Each isolate has its own memory space and cannot access the host process or other isolates. Startup time is measured in milliseconds, not seconds.<\/p>\n<p>When a hook triggers a plugin, EmDash spins up a fresh isolate, passes the plugin code and the event data, and lets the plugin execute within its declared capabilities. The isolate is destroyed after execution. There is no persistent state that a malicious plugin could exploit.<\/p>\n<p>The catch: the full sandbox only works on Cloudflare&#8217;s paid plan ($5\/month). Self-hosted EmDash on a regular Node.js server runs plugins in-process without isolation. On the free Cloudflare tier, plugins also run in-process. The security model that justifies EmDash&#8217;s existence requires Cloudflare&#8217;s infrastructure.<\/p>\n<h2>Granular API Token Permissions<\/h2>\n<p>EmDash includes a built-in API token system with scoped permissions. You can generate a token that grants only &#8220;content read&#8221; access, or only &#8220;content write&#8221; for a specific content type. Tokens can have an expiration date.<\/p>\n<p>This is useful for third-party integrations. For example, a static site generator that pulls content from EmDash for build-time rendering only needs read access. You create a token with the &#8220;content read&#8221; capability, set it to expire in 90 days, and give it to the build script. If the token leaks, the attacker cannot write or delete anything.<\/p>\n<p>In WordPress, API tokens (application passwords) give full access to the REST API unless you use a third-party plugin to scope them. EmDash makes scoping the default.<\/p>\n<h2>User Management and Invitation System<\/h2>\n<p>Creating a new user in EmDash is straightforward. An administrator enters an email address and selects a role. The system sends an invitation. The new user authenticates with a passkey\u2014no password to leak, no brute-force vector.<\/p>\n<p>Passkeys are device-bound cryptographic credentials. They are not stored on a server. Even if EmDash&#8217;s database is compromised, user credentials are safe. The authentication system uses WebAuthn, a web standard supported by all major browsers.<\/p>\n<p>One practical problem: passkeys are tied to the device and the origin. A developer running 50 EmDash sites locally on localhost will have 50 passkeys, one per site. That is manageable but not elegant. Cloudflare has not announced a solution for multi-site passkey management.<\/p>\n<h2>Content Type Permissions<\/h2>\n<p>EmDash allows administrators to create custom content types through the admin interface. You define fields, slugs, and URL patterns. This is done in the database, not in code.<\/p>\n<p>Permissions for custom content types follow the same role-based model. An editor can edit any content of any type. An author can edit only their own content of any type. There is no field-level permission\u2014if an editor can edit a &#8220;project&#8221; content type, they can edit all fields within that project. You cannot restrict access to a specific field (e.g., &#8220;price&#8221; field visible only to administrators).<\/p>\n<p>This is a limitation compared to advanced WordPress setups using plugins like Advanced Custom Fields (ACF) with role-based field visibility. EmDash&#8217;s content type system is simpler and less granular.<\/p>\n<h2>Comparison: WordPress vs. EmDash Permission Models<\/h2>\n<table class=\"mw-table\">\n<thead>\n<tr>\n<th>Feature<\/th>\n<th>WordPress<\/th>\n<th>EmDash<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Plugin database access<\/td>\n<td>Full (via <code>wpdb<\/code>codecodecode)<\/td>\n<td>Only declared capabilities<\/td>\n<\/tr>\n<tr>\n<td>Plugin network access<\/td>\n<td>Full<\/td>\n<td>Only if declared in manifest<\/td>\n<\/tr>\n<tr>\n<td>User authentication<\/td>\n<td>Password (or 2FA plugin)<\/td>\n<td>Passkey by default<\/td>\n<\/tr>\n<tr>\n<td>API token scoping<\/td>\n<td>Third-party plugin<\/td>\n<td>Built-in, per-capability<\/td>\n<\/tr>\n<tr>\n<td>Custom content types<\/td>\n<td>Requires plugin (e.g., ACF)<\/td>\n<td>Built-in, but database-defined<\/td>\n<\/tr>\n<tr>\n<td>Field-level permissions<\/td>\n<td>Possible with plugins<\/td>\n<td>Not available<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The most significant difference is plugin security. In 2025, security researchers disclosed 11,334 new WordPress vulnerabilities. 96% came from plugins. In an analysis of 500 reported plugin vulnerabilities from that year, roughly 78% involved unauthorized database reads or writes\u2014an attack vector the EmDash sandbox model physically blocks.<\/p>\n<h2>Practical Scenarios and Best Practices<\/h2>\n<h3>Scenario 1: Agency with 50 Client Sites<\/h3>\n<p>An agency managing multiple EmDash sites will need a separate passkey for each site. This is inconvenient but secure. The alternative is to use API tokens for automated tasks and passkeys only for manual administration. The agency should store passkeys in a password manager that supports WebAuthn.<\/p>\n<h3>Scenario 2: Developer Building a Custom Plugin<\/h3>\n<p>When building a plugin, declare only the capabilities you need. If the plugin sends emails, declare &#8220;send email.&#8221; Do not declare &#8220;write content&#8221; unless the plugin actually creates posts. This limits the blast radius if the plugin is compromised. Test the plugin on the free Cloudflare tier first (in-process mode), then deploy on the paid plan for sandboxed execution.<\/p>\n<h3>Scenario 3: Content Team with Editors and Authors<\/h3>\n<p>Set editors as the highest non-admin role. Authors can publish their own posts. Contributors submit drafts. This mirrors a standard WordPress workflow, but with the added assurance that no plugin can escalate an author&#8217;s privileges.<\/p>\n<h2>Security Implications of the Permission Model<\/h2>\n<p>The architectural enforcement of permissions eliminates entire classes of attacks. A compromised plugin cannot:<\/p>\n<ul>\n<li>Read password hashes (no database access)<\/li>\n<li>Create admin users (no user management capabilities)<\/li>\n<li>Inject malicious JavaScript into the admin panel (no write access to core files)<\/li>\n<li>Use the server for cryptocurrency mining (no unrestricted network access)<\/li>\n<\/ul>\n<p>These are not hypothetical. In the WordPress ecosystem, plugins are the primary attack surface. EmDash&#8217;s sandbox is not a cure-all\u2014self-hosted instances lose the sandbox\u2014but on Cloudflare&#8217;s infrastructure, the model is sound.<\/p>\n<h2>Limitations and Edge Cases<\/h2>\n<ul>\n<li><strong>Self-hosted loses sandbox<\/strong>: If you run EmDash on your own Node.js server, plugins run in-process. The security advantage disappears. You are left with a new CMS with zero plugins and no ecosystem.<\/li>\n<li><strong>No custom roles<\/strong>: Only four roles are available. You cannot create a &#8220;SEO Manager&#8221; role that can edit only SEO fields. WordPress plugins like Members or User Role Editor allow this.<\/li>\n<li><strong>No field-level permissions<\/strong>: Within a content type, all fields are visible to all roles that can edit that type. Sensitive fields (e.g., internal notes) cannot be hidden from editors.<\/li>\n<li><strong>Passkey portability<\/strong>: Passkeys are bound to the device and origin. Moving between devices or sharing access requires re-enrollment.<\/li>\n<\/ul>\n<p>These limitations are by design. EmDash prioritizes simplicity and security over granularity. For most content teams, the four roles are sufficient. For complex enterprise workflows, the lack of custom roles may be a dealbreaker.<\/p>\n<p>EmDash&#8217;s permission model is a clean restart of the WordPress approach. It removes the implicit trust that WordPress places in plugins and replaces it with explicit, auditable declarations. The trade-off is a smaller ecosystem and a dependency on Cloudflare&#8217;s runtime for the full security model. For teams that value security over plugin abundance, EmDash is worth evaluating today. For everyone else, the WordPress ecosystem still offers more flexibility\u2014but at a measurable security cost.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>WordPress plugins have full database access by design. Install a contact form plugin with a bug, and an attacker can read your entire user table. That&#8217;s not a flaw in the plugin\u2014it&#8217;s how the architecture was built. EmDash, Cloudflare&#8217;s spiritual successor to WordPress, fixes this with a permission model that starts at the code level. [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":99341,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/cards.overcentral.com\/cards\/en\/98031.png","fifu_image_alt":"EmDash User Roles and Permissions: The Complete Guide","footnotes":""},"categories":[31],"tags":[],"class_list":["post-98031","post","type-post","status-publish","format-standard","has-post-thumbnail","category-technology"],"fifu_image_url":"https:\/\/cards.overcentral.com\/cards\/en\/98031.png","fifu_image_alt":"EmDash User Roles and Permissions: The Complete Guide","_links":{"self":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98031","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/comments?post=98031"}],"version-history":[{"count":1,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98031\/revisions"}],"predecessor-version":[{"id":99342,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/posts\/98031\/revisions\/99342"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/media\/99341"}],"wp:attachment":[{"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/media?parent=98031"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/categories?post=98031"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/overcentral.com\/en\/wp-json\/wp\/v2\/tags?post=98031"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}