<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>pkcarreno</title><description>The journal of pk</description><link>https://pkcarreno.com/</link><language>en</language><item><title>How to Make Antigravity Tolerable</title><link>https://pkcarreno.com/journal/how-to-make-antigravity-tolerable/</link><guid isPermaLink="true">https://pkcarreno.com/journal/how-to-make-antigravity-tolerable/</guid><description>A custom permission setup for antigravity-cli that stops constant prompts and makes the CLI experience feel closer to harnesses like OpenCode.</description><pubDate>Wed, 05 Aug 2026 20:14:26 GMT</pubDate><content:encoded>&lt;h1&gt;How to Make Antigravity Tolerable&lt;/h1&gt;
&lt;p&gt;Antigravity is the least efficient tool I have used for development, though
&lt;code&gt;antigravity-cli&lt;/code&gt; (&lt;code&gt;agy&lt;/code&gt;) is the least bad of the three. Still, the experience
falls far short of harnesses like OpenCode or Claude Code.&lt;/p&gt;
&lt;p&gt;I wanted to make good use of my Antigravity quota, so I tweaked a configuration
that makes using it much more bearable.&lt;/p&gt;
&lt;p&gt;My main issue with Antigravity was its constant confirmation prompts. Unlike
OpenCode, Antigravity uses a strict permission model that asks before running
even the smallest action.&lt;/p&gt;
&lt;p&gt;To fix this, I expanded Antigravity&apos;s default permissions. The core principle is
simple: grant broad access by default, then selectively block high-risk
operations that could be catastrophic.&lt;/p&gt;
&lt;p&gt;Open &lt;code&gt;~/.gemini/antigravity-cli/settings.json&lt;/code&gt; and paste the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;permissions&quot;: {
    &quot;allow&quot;: [
      &quot;command(*)&quot;,
      &quot;read_file(*)&quot;,
      &quot;write_file(./*)&quot;,
      &quot;write_file(src/)&quot;,
      &quot;read_url(*)&quot;,
      &quot;mcp(*)&quot;
    ],
    &quot;deny&quot;: [
      &quot;read_file(**/*.key)&quot;,
      &quot;read_file(**/*.pem)&quot;,
      &quot;read_file(**/.aws/credentials)&quot;,
      &quot;read_file(**/.config/gh/hosts.yml)&quot;,
      &quot;read_file(**/.credentials/**)&quot;,
      &quot;read_file(**/.env)&quot;,
      &quot;read_file(**/.env.*)&quot;,
      &quot;read_file(**/.ssh/**)&quot;,
      &quot;read_file(**/Library/Keychains/**)&quot;,
      &quot;read_file(**/credentials.json)&quot;,
      &quot;read_file(**/secrets/**)&quot;,
      &quot;read_file(*.env)&quot;,
      &quot;read_file(*.env.*)&quot;,
      &quot;write_file(**/.git/**)&quot;,
      &quot;command(chmod *)&quot;,
      &quot;command(chown *)&quot;,
      &quot;command(rm -rf)&quot;,
      &quot;command(sudo)&quot;,
      &quot;command(git reset --hard)&quot;,
      &quot;command(git checkout -- *)&quot;,
      &quot;command(git restore)&quot;,
      &quot;command(git clean -f)&quot;,
      &quot;command(git push --force)&quot;,
      &quot;command(git branch -D)&quot;,
      &quot;command(git stash drop)&quot;,
      &quot;command(git stash clear)&quot;
    ],
    &quot;ask&quot;: [
      &quot;write_file(../**)&quot;,
      &quot;command(rm *)&quot;,
      &quot;command(git commit *)&quot;,
      &quot;command(git push)&quot;,
      &quot;command(git push *)&quot;,
      &quot;command(git rebase *)&quot;,
      &quot;command(git reset --hard *)&quot;,
      &quot;command(git merge *)&quot;
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;I tested this setup on &lt;code&gt;antigravity-cli&lt;/code&gt;; I cannot confirm whether it works on
other versions of Antigravity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I put together this setup based on the design principles of OpenCode and
Antigravity, as well as the
&lt;a href=&quot;https://github.com/Gentleman-Programming/gentle-ai&quot;&gt;gentle-ai&lt;/a&gt; standards. Feel
free to adapt this setup to your own stack and local tools. The goal is to close
dangerous vectors without slowing down your workflow. Understand each rule
before applying it.&lt;/p&gt;
&lt;p&gt;Current Google models (gemini-3.1-pro, gemini-3.5-flash, gemini-3.6-flash) still
struggle with tool calls. I only use them for simple, low-complexity tasks.&lt;/p&gt;
&lt;p&gt;I cannot recommend Antigravity, but if you must use it, I hope this
configuration helps.&lt;/p&gt;
&lt;p&gt;For more details, see the &lt;code&gt;antigravity-cli&lt;/code&gt; permissions documentation:
&lt;a href=&quot;https://antigravity.google/docs/cli/permissions&quot;&gt;https://antigravity.google/docs/cli/permissions&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>ai</category><category>tools</category><author>34664891+Pkcarreno@users.noreply.github.com (pk)</author><source url="https://pkcarreno.com/journal">journals</source></item><item><title>The Hidden Language</title><link>https://pkcarreno.com/journal/the-hidden-language/</link><guid isPermaLink="true">https://pkcarreno.com/journal/the-hidden-language/</guid><description>I read this book to help in my adventure of learning a low-level language. It gets dense, but it helped me connect the dots on how computers work.</description><pubDate>Sun, 01 Feb 2026 14:51:45 GMT</pubDate><content:encoded>&lt;h1&gt;The Hidden Language&lt;/h1&gt;
&lt;p&gt;On my adventure to learn a low-level language, many recommended the book
&lt;a href=&quot;https://www.goodreads.com/book/show/44882.Code&quot;&gt;Code: The Hidden Language of Computer Hardware and Software&lt;/a&gt;
by Charles Petzold. The description looked interesting, so I decided to buy it.&lt;/p&gt;
&lt;p&gt;The book takes you on a step-by-step and incremental journey through all the
main concepts that make it possible for a computer to work.&lt;/p&gt;
&lt;p&gt;It helped me connect separate ideas that have always been said about how
computers work, but with solid foundations explained in a logical way that is
easy to digest.&lt;/p&gt;
&lt;p&gt;Though, I&apos;m not going to lie, the last chapters are somewhat dense, since you
have to keep in mind everything said in the previous chapters for it to make
sense.&lt;/p&gt;
&lt;p&gt;It&apos;s a book I recommend, whether you want to understand how low-level languages
act, or if you just want to understand how computers work.&lt;/p&gt;
</content:encoded><category>hardware</category><category>book</category><author>34664891+Pkcarreno@users.noreply.github.com (pk)</author><source url="https://pkcarreno.com/journal">journals</source></item><item><title>All the ways to run JavaScript in the browser</title><link>https://pkcarreno.com/journal/all-the-ways-to-run-javascript-in-the-browser/</link><guid isPermaLink="true">https://pkcarreno.com/journal/all-the-ways-to-run-javascript-in-the-browser/</guid><description>A deep dive into secure client-side javascript execution. From native eval to WebAssembly engines, everything I learned while developing Glyphide.</description><pubDate>Wed, 21 Jan 2026 13:40:07 GMT</pubDate><content:encoded>&lt;h1&gt;All the ways to run JavaScript in the browser&lt;/h1&gt;
&lt;p&gt;This information is part of a research I originally did in December 2023 during
the early development stages of &lt;a href=&quot;/projects/glyphide&quot;&gt;glyphide&lt;/a&gt;. I&apos;ve reviewed
and updated these findings to validate the state of the art in 2026 and offer a
precise guide on client-side code execution.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The information about Glyphide in this article applies to version 2.
Glyphide had a major architectural change. Because of this, some technical
details in this text do not apply to version 3 and later.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Being able to run arbitrary javascript code in the browser securely is a
colossal task. The complexity is such that many commercial tools choose to avoid
the problem entirely by delegating execution to an external server or services
like cloudflare workers.&lt;/p&gt;
&lt;p&gt;However, client-side execution offers unmatched latency and privacy advantages.
In this article I&apos;ll explore the different strategies available from native
methods (and why I decided not to use them) to external engines based on
WebAssembly (WASM) detailing the technical path that led me to the final
architecture of glyphide.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#previous-considerations&quot;&gt;previous considerations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#exploration-of-execution-methods&quot;&gt;exploration of execution methods&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#native-approaches&quot;&gt;native approaches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mitigation-strategies&quot;&gt;mitigation strategies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#external-libraries&quot;&gt;external libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#conclusions&quot;&gt;conclusions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#references&quot;&gt;references&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;previous considerations&lt;/h2&gt;
&lt;p&gt;Building a secure execution enviroment is the ultimate challenge when handling
arbitrary code. The browser is a critical context because besides containing
sensitive data that must be protected, there is a risk that the injected code
could use your own domain as a bridge to attack your infrastructure bypassing
external security controls.&lt;/p&gt;
&lt;p&gt;During my research for glyphide I defined a mental framework of three critical
questions to evaluate the viability of each method. These are not just
theoretical questions, they are the real attack vectors that will determine if
your application is secure or a ticking time bomb.&lt;/p&gt;
&lt;h3&gt;1. can the executed code modify the host enviroment?&lt;/h3&gt;
&lt;p&gt;This is the integrity test. Javascript is a dynamic and extremely flexible
language which is its greatest virtue and its worst defect in this context.&lt;/p&gt;
&lt;p&gt;The risk here is not just that the code &quot;reads&quot; variables but that it modifies
the base behavior of the browser. If the executed code shares the same global
object (window/globalThis) it could perform a prototype pollution attack.
Imagine a malicious script rewriting &lt;code&gt;Array.prototype.map&lt;/code&gt;. Suddenly all your
&quot;secure&quot; code that uses arrays starts behaving unpredictably or sending data to
an external server.&lt;/p&gt;
&lt;p&gt;If the enviroment does not isolate globals properly the guest code can destroy
the host application simply by overwriting native functions.&lt;/p&gt;
&lt;h3&gt;2. can the executed code access secrets or user data?&lt;/h3&gt;
&lt;p&gt;This is the confidentiality test. The browser is a vault of secrets including
authentication tokens in &lt;code&gt;localStorage&lt;/code&gt;, session cookies in &lt;code&gt;document.cookie&lt;/code&gt;
and private data in memory.&lt;/p&gt;
&lt;p&gt;If you execute arbitrary code without strict isolation you are effectively
creating a self-inflicted XSS (Cross-Site Scripting) vulnerability. The injected
code could make &lt;code&gt;fetch&lt;/code&gt; calls to your backend API using the logged-in user
credentials performing actions on their behalf without them knowing.&lt;/p&gt;
&lt;p&gt;The key question here is whether the code can see anything beyond it&apos;s own
declared variables.&lt;/p&gt;
&lt;h3&gt;3. can the executed code block the main thread?&lt;/h3&gt;
&lt;p&gt;This is the availability test. Unlike other languages, javascript generally runs
on a single thread which it shares with the interface rendering.&lt;/p&gt;
&lt;p&gt;This is the classic main thread blocking problem. If a user writes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;while (true) {
  console.log(&quot;oops&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a poorly isolated enviroment (like a simple &lt;code&gt;try-catch&lt;/code&gt; around an &lt;code&gt;eval&lt;/code&gt;) the
entire browser will freeze. You will not be able to close the tab or click
&quot;stop&quot; and the only way out will be killing the browser process. For tools like
glyphide where user experience is vital, allowing a syntax error to block the UI
is unacceptable.&lt;/p&gt;
&lt;h2&gt;exploration of execution methods&lt;/h2&gt;
&lt;h3&gt;native approaches&lt;/h3&gt;
&lt;p&gt;I refer to native methods as all those functions or strategies for executing
javascript that are integrated into the browser. These options can be quite
counterintuitive regarding what one might think.&lt;/p&gt;
&lt;p&gt;These methods are the base upon which more complex abstractions are built, but
their direct use is plaged by technical subtleties and security dangers.&lt;/p&gt;
&lt;h4&gt;eval&lt;/h4&gt;
&lt;p&gt;The
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval&quot;&gt;eval&lt;/a&gt;
function is the most primitive mechanism for dynamic execution. It&apos;s behavior
varies depending on the syntax used to invoke it.&lt;/p&gt;
&lt;p&gt;There is a distinction between direct mode and indirect mode and it&apos;s a
distinction that has implications on the scope they can reach as well as the
optimization of the javascript engine.&lt;/p&gt;
&lt;h5&gt;direct eval&lt;/h5&gt;
&lt;p&gt;Direct eval occurs when the function is invoked using the identifier &lt;code&gt;eval&lt;/code&gt;
within a function. When executed the evaluated code shares the lexical
enviroment of the calling context. This means the injected code has read and
write access to local variables function arguments and active closures.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  var secret = &quot;private_key&quot;;
  eval(&quot;console.log(secret)&quot;); // has access to the local variable
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From a security perspective this is catastrophic as it breaks the encapsulation
principle. A malicious script injected via direct eval can exfiltrate sensitive
data that the developer assumed was private within the function scope.&lt;/p&gt;
&lt;p&gt;Furthermore, modern engines rely heavily on speculative optimizations and
just-in-time compilation. To optimize variable access the engine must know at
compile time where each variable resides in memory. The presence of a direct
eval prevents these optimizations since eval can introduce new variables that
shadow existing ones and the engine cannot assume the sctructure of the lexical
scope. As a result the code surrounding a direct eval often runs in a &quot;slow&quot;
mode disabling critical optimizations like inline caching.&lt;/p&gt;
&lt;h5&gt;indirect eval&lt;/h5&gt;
&lt;p&gt;This occurs when the &lt;code&gt;eval&lt;/code&gt; function is invoked through a reference.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function demo() {
  var secret = &quot;private_key&quot;;
  var globalEval = eval;
  globalEval(&quot;console.log(secret)&quot;); // secret is not defined
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unlike direct eval this executes the code in the global scope. It does not have
access to local variables of the calling context and this provides a superficial
layer of security as it avoids accidental leakage of local variables. However,
the executed code still has acces to the global object which allows it to access
all global APIs, the DOM, cookies and local storage.&lt;/p&gt;
&lt;h3&gt;new function&lt;/h3&gt;
&lt;p&gt;The
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function&quot;&gt;new Function()&lt;/a&gt;
constructor is frequently recommended as a superior alternative to &lt;code&gt;eval&lt;/code&gt;. It
creates a function whose body is the provided string. Unlike statically declared
functions the body of a function generated with this constructor is parsed only
at the moment of object creation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const add = new Function(&quot;a&quot;, &quot;b&quot;, &quot;return a + b&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Functions created this way always execute in the global scope and do not capture
the lexical enviroment of their creation. This makes them functionally similar
to indirect eval in terms of local variable isolation. However, they share the
same unrestricted access to the global object. An attacker can execute
&lt;code&gt;new Functions(&apos;return document.cookie&apos;)()&lt;/code&gt; to steal credentials.&lt;/p&gt;
&lt;p&gt;Although &lt;code&gt;new Function&lt;/code&gt; avoids some of the performance problems of direct eval
it remains an XSS attack vector. Additionally modern content security policies
(CSP) often block &lt;code&gt;new Function&lt;/code&gt; under the same &lt;code&gt;unsafe-eval&lt;/code&gt; directive that
blocks &lt;code&gt;eval&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;iframe&lt;/h3&gt;
&lt;p&gt;The
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/iframe&quot;&gt;&amp;lt;iframe&amp;gt;&lt;/a&gt;
element has evolved from being a simple container for embedded content to a
fundamental security tool thanks to the &lt;code&gt;sandbox&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;sandbox&lt;/code&gt; attribute imposes a series of restrictions on the &lt;code&gt;iframe&lt;/code&gt; content
disabling scripts and forcing the content to be treated as if it came from a
unique and opaque origin even if the URL is from the same domain.&lt;/p&gt;
&lt;p&gt;To execute javascript code one must relax the &lt;code&gt;allow-scripts&lt;/code&gt; policy. But you
must avoid at all costs combining this attribute with &lt;code&gt;allow-same-origin&lt;/code&gt;
because the code inside could access the parent DOM and with this the element
itself could contain a script that navigates the parent DOM until finding it&apos;s
own &lt;code&gt;iframe&lt;/code&gt; element and removing the &lt;code&gt;sandbox&lt;/code&gt; attribute which would leave it
just as exposed as if no protection existed.&lt;/p&gt;
&lt;p&gt;When you do not have the &lt;code&gt;allow-same-origin&lt;/code&gt; attribute the only form of
communication is through the &lt;code&gt;postMessage&lt;/code&gt; API which can send data and listen
for &lt;code&gt;message&lt;/code&gt; events. Transferred data must be serializable which implies that
functions or objects or complex class instances cannot be passed and this
complicates the implementation of callbacks or the injection of custom APIs into
the sandbox.&lt;/p&gt;
&lt;h3&gt;shadowrealms&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/tc39/proposal-shadowrealm&quot;&gt;ShadowRealms&lt;/a&gt; proposal of the
ECMA standard seeks to introduce a new native primitive that allows creating
isolated evaluation environments.&lt;/p&gt;
&lt;p&gt;It would allow creating a new global object and evaluating code inside it
synchronously.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const realm = new ShadowRealm();
const result = realm.evaluate(&quot;2 + 2&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ShadowRealm&lt;/code&gt; guarantees integrity as the code cannot modify the parent code.
However, it is important to note that it does not guarantee confidentiality.
Since it runs in the same process, it is vulnerable to side-channel attacks like
spectre so it should not be used to isolate secrets from hostile code.&lt;/p&gt;
&lt;p&gt;It also does not offer protection against main thread blocking. If an infinite
loop runs in the ShadowRealm it would block the parent context as well. Although
there will surely be techniques to combine this with a web worker and handle
these types of cases.&lt;/p&gt;
&lt;p&gt;As of today (January 2026) the proposal is at stage 2.7 but is not yet a
finalized standard.&lt;/p&gt;
&lt;h3&gt;mitigation strategies&lt;/h3&gt;
&lt;p&gt;Before discarding native methods, I tried to implement a series of strategies to
mitigate the security and stability risks mentioned previously. The premise was
trying to &quot;sanitize&quot; native execution instead of replacing the engine.&lt;/p&gt;
&lt;p&gt;These techniques focused on wrapping the user code in a controlled environment
before passing it to an &lt;code&gt;eval&lt;/code&gt; or &lt;code&gt;new Function&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;context isolation &amp;amp; mocking&lt;/h4&gt;
&lt;p&gt;To avoid access to the real global object the common strategy is to use the
&lt;code&gt;with&lt;/code&gt; statement (even though it is deprecated or forbidden in strict mode) or
Proxies to create a &quot;fake global&quot;.&lt;/p&gt;
&lt;p&gt;The idea is to create an empty object or whitelist where we inject only what we
want the user to use and mask everything else.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const sandboxContext = {
  window: null,
  document: null,
  console: {
    log: (msg) =&amp;gt; myCustomLogger(msg), // capture output
  },
};

// conceptual execution wrapper with &apos;with&apos; logic
new Function(&quot;sandbox&quot;, &quot;with(sandbox) { return &quot; + userCode + &quot;}&quot;)(
  sandboxContext,
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This also solved output capturing. By overwriting &lt;code&gt;console&lt;/code&gt; methods I could
redirect messages to the glyphide terminal instead of the developer&apos;s browser
console.&lt;/p&gt;
&lt;h4&gt;infinite loop protection&lt;/h4&gt;
&lt;p&gt;To prevent main thread blocking the only way to protect the UI without using web
workers is code instrumentation.&lt;/p&gt;
&lt;p&gt;This implied using tools like Babel to analyze the Abstract Syntax Tree (AST) of
the user code and inject a counter inside every infinite loop (&lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;,
&lt;code&gt;do-while&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// user code
while (true) {}

// transformed code by babel
let _counter = 0;
while (true) {
  _counter++;
  if (_counter &amp;gt; 1000) throw new Error(&quot;Execution time limit exceeded&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this worked for explicit loops it proved insufficient for more complex
cases like recursion. Detecting if a recursive function will cause an infinite
loop or is simply a deep calculation is extremely difficult.&lt;/p&gt;
&lt;p&gt;To protect against this, one would have to instrument every function call which
adds massive performance overhead. Furthermore programmatically determining the
boundary between legitimate recursion and a crash is arbitrary and in many cases
impossible to predict accurately without breaking valid code.&lt;/p&gt;
&lt;h4&gt;why i discarded it&lt;/h4&gt;
&lt;p&gt;Although on paper it sounds viable, in practice it turned out to be an
unreliable solution.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cat and mouse game: javascript evolves constantly. New global features or new
syntax can break the sandbox or escape the logic of &lt;code&gt;with&lt;/code&gt; or Proxies.&lt;/li&gt;
&lt;li&gt;Performance overhead: Parsing and transforming code with Babel on the client
before each execution adds perceptible latency.&lt;/li&gt;
&lt;li&gt;Browser inconsistencies: The way different browsers handle certain scope edge
cases made maintenance a huge burden.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The conclusion was that trying to secure an environment that is insecure by
design was much more expensive and risky than implementing a secure environment
from scratch like the ones we will see next.&lt;/p&gt;
&lt;h3&gt;external libraries&lt;/h3&gt;
&lt;p&gt;This type refers to those methods that require the use of libraries to achieve
javascript execution in a secure environment. This is where WebAssembly (WASM)
frequently comes into play although it is not the only strategy.&lt;/p&gt;
&lt;p&gt;Unlike native methods where we try to contain the browser javascript engine,
here we are instantiating a complete javascript engine (or a robust simulation)
that operates independently. This usually creates a &quot;perfect sandbox&quot; by design
especially in WASM implementations where the code inside has no access to
browser memory or the DOM unless we explicitly allow it.&lt;/p&gt;
&lt;p&gt;The technical challenge here stops being isolation and becomes marshalling (Data
Serialization). Moving complex objects between the browser javascript and the
external engine is expensive and requires serialization.&lt;/p&gt;
&lt;h4&gt;quick-js&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://bellard.org/quickjs/&quot;&gt;quick-js&lt;/a&gt; is a lightweight javascript engine that
supports the ES2023 specification.&lt;/p&gt;
&lt;p&gt;Its great advantage is that it is extremely small and fast to boot which makes
it ideal for compiling to WASM using &lt;a href=&quot;https://emscripten.org/&quot;&gt;emscripten&lt;/a&gt;. Here
we are not executing javascript directly, we are executing a C interpreter
compiled to bytecode which in turn interprets the javascript. Thanks to
libraries like
&lt;a href=&quot;https://github.com/justjake/quickjs-emscripten&quot;&gt;quickjs-emscripten&lt;/a&gt; we can
instantiate this engine in the browser.&lt;/p&gt;
&lt;p&gt;Security is maximum but the technical limitation is data synchronization. Every
time you want to pass an object to the secure environment you must copy it to
the WASM module memory and vice versa (marshalling) which adds computable
overhead.&lt;/p&gt;
&lt;p&gt;A basic example of raw usage would be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { getQuickJS } from &quot;quickjs-emscripten&quot;;

async function run() {
  const QuickJS = await getQuickJS();
  const vm = QuickJS.newContext(); // Create a new environment

  const result = vm.evalCode(&quot;1 + 1&quot;);

  if (result.error) {
    console.error(&quot;Execution failed:&quot;, vm.dump(result.error));
    result.error.dispose();
  } else {
    console.log(&quot;Result:&quot;, vm.dump(result.value)); // Logs: 2
    result.value.dispose();
  }

  vm.dispose(); // Cleanup is manual and mandatory
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;quickjs-emscripten-sync&lt;/h5&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/reearth/quickjs-emscripten-sync&quot;&gt;quickjs-emscripten-sync&lt;/a&gt;
was one of the first abstractions I tested and its name refers to it&apos;s core
capability that is synchonizing objects state between the host and the isolated
enviroment.&lt;/p&gt;
&lt;p&gt;Its great contribution is automating marshalling and object lifecycle. It allows
exchanging primitives arrays classes and promises seamlessly. Thanks to the use
of &lt;code&gt;Proxies&lt;/code&gt; it allows modifications on a shared object to be automatically
reflected on the other side without having to manage pointers manually.&lt;/p&gt;
&lt;p&gt;However, it has a practical limitation regarding orchestration. Although it
supports promises, the communication between the host and the sandbox is
fundamentally synchronous during function calls. If you inject a host function
that performs an asynchronous operation (like &lt;code&gt;fetch&lt;/code&gt;) and returns a promise the
quickjs engine does not automatically pause its execution to wait for the host.
This complicates the implementation of APIs where the sandbox code must wait for
the result of a network or I/O operation from the browser before continuing to
the next instruction line.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Arena } from &quot;quickjs-emscripten-sync&quot;
import { getQuickJS } from &quot;quickjs-emscripten&quot;

async function run() {
  const ctx = (await getQuickJS()).newContext()
  // &quot;Arena&quot; manages automatic marshalling and state sync
  const arena = new Arena(ctx, { isMarshalable: true })

  // We can sync an object state bidirectionally
  const sharedState = arena.sync({ count: 0 })
  arena.expose({ sharedState })

  // Code runs and modifies the shared object
  arena evalCode(&apos;sharedState.count += 1&apos;)

  // The change is reflected in the host immediately
  console.log(sharedState.count) // 1

  arena.dispose()
  ctx.dispose()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;@sebastianwessel/quickjs&lt;/h5&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sebastianwessel/quickjs&quot;&gt;@sebastianwessel/quikjs&lt;/a&gt; is a
comprehensive abstraction that builds upon &lt;code&gt;quickjs-emscripten&lt;/code&gt; to provide a
feature-rich enviroment. It solves the limitations of &lt;code&gt;quickjs-emscripten-sync&lt;/code&gt;
by offering not just a raw engine but a runtime that includes support for basic
Node.js modules, a virtual file system and a built-in test runner.&lt;/p&gt;
&lt;p&gt;Crucially it resolves the asynchronous execution gap. It provides a fetch client
that allows code inside the sandbox to perform http request securely. This make
it possible to run realistic code that interacts with APIs without leaving the
isolated WebAssembly enviroment.&lt;/p&gt;
&lt;p&gt;It also includes support for executing typescript code directly. However, it&apos;s
important to note that this operates via a syntax-stripping process on the fly.
It allows the engine to parse and run typescript files by ignoring type
annotations but it does not perform type validation at runtime.&lt;/p&gt;
&lt;h5&gt;hako&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;[not tested]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/6over3/hako&quot;&gt;hako&lt;/a&gt; is an engine built on top of a &lt;code&gt;quick-js&lt;/code&gt;
fork compiled to WASM. It&apos;s value proposition is simplicity and support for
typescript.&lt;/p&gt;
&lt;p&gt;It employs the same syntax-stripping mechanism as &lt;code&gt;@sebastianwessel/quickjs&lt;/code&gt; to
run typescript code directly ignoring type annotations during execution without
performing validation.&lt;/p&gt;
&lt;p&gt;I have not tested this one as it&apos;s relatively new at the time of writing this
article. However, it catches my attention to run a test with it and see what
advantages it could bring to glyphide.&lt;/p&gt;
&lt;h4&gt;ducktape&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://duktape.org/&quot;&gt;duktape&lt;/a&gt; is an ES5 engine (with parts of ES6) designed
originally for embedded systems with very limited resources.&lt;/p&gt;
&lt;p&gt;I managed to do a minimal test of this and it works quite well as stated. It has
a reputation for stability with a minimal footprint in size and memory. However,
it&apos;s ECMA standard limitations made me discard it quickly. If your main
constraint is initial load time and you do not need modern javascript
functionalities (like &lt;code&gt;async/await&lt;/code&gt;) this is the way.&lt;/p&gt;
&lt;h4&gt;repl&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;[not tested]&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/stdlib-js/repl&quot;&gt;repl&lt;/a&gt; from the stdlib-js organization is not
an engine itself but an implementation of the REPL (Read-Eval-Print Loop)
interface designed for scientific computing.&lt;/p&gt;
&lt;p&gt;I have not experimented with it but I can responsibly assume that this library
makes significant cuts in javascript capabilities to achieve secure execution,
limiting itself to it&apos;s purpose which is numerical and scientific calculation
capabilities instead of being a general-purpose environment.&lt;/p&gt;
&lt;h4&gt;webcontainers&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://webcontainers.io/&quot;&gt;WebContainers&lt;/a&gt; plays in a different league. It&apos;s not
just a javascript engine, but a virtualized operating system over the browser.
It&apos;s based on WebAssembly and is the engine behind tools like StackBlitz.&lt;/p&gt;
&lt;p&gt;The technical magic here is not just WASM but the intensive use of Service
Workers and SharedArrayBuffer. WebContainers manages to virtualize the network
layer and the file system inside the browser. When you execute &lt;code&gt;npm install&lt;/code&gt;
inside a WebContainer the Service Worker intercepts network requests and handles
them allowing a complete Node.js environment to function without a backend.&lt;/p&gt;
&lt;p&gt;I managed to have an operative model in glyphide during the experimentation
phase. Its implementation is spectacularly simple and worked very well. The fact
that it&apos;s a node environment means that features like importing libraries were
easy to carry out.&lt;/p&gt;
&lt;p&gt;Something to keep in mind and the reason why I discarded it is that it&apos;s not an
open-source or permissive technology. It&apos;s very easy to integrate but imposes
considerable limitations for your project or future expansions (requires usage
of their services for booting and very strict HTTP security headers like
&lt;code&gt;Cross-Origin-Embedder-Policy&lt;/code&gt; and &lt;code&gt;Cross-Origin-Opener-Policy&lt;/code&gt;). This is
something important to take into account.&lt;/p&gt;
&lt;h2&gt;conclusions&lt;/h2&gt;
&lt;p&gt;For the specific case of &lt;a href=&quot;/projects/glyphide&quot;&gt;glyphide&lt;/a&gt; the final choice was
&lt;strong&gt;quickjs&lt;/strong&gt;, implemented specifically through the library
@sebastianwessel/quickjs.&lt;/p&gt;
&lt;p&gt;Another decisive factor was &lt;strong&gt;consistency&lt;/strong&gt;. By using a self-contained engine in
WebAssembly, execution is deterministic: it does not depend on the user&apos;s
browser engine or its version. This guarantees that if the code works on my
machine it will work exactly the same on any other device, eliminating
cross-browser compatibility problems.&lt;/p&gt;
&lt;p&gt;Initially I used &lt;code&gt;quickjs-emscripten-sync&lt;/code&gt; for its ease of integration, but the
need to support asynchronous operations was decisive for migrating. The ability
to handle promises and asynchronous APIs of the Sebastian Wessel library was
what allowed offering a realistic development experience.&lt;/p&gt;
&lt;p&gt;This choice was complemented by integrating the engine inside a web worker. This
combination is what really shields the application: quickjs protects integrity
and confidentiality while the web worker protects availability, preventing an
infinite loop from freezing the user interface.&lt;/p&gt;
&lt;p&gt;Looking into the future, the discovery of &lt;em&gt;hako&lt;/em&gt; during this research seems
promising. It&apos;s a clear demonstration that the secure execution ecosystem keeps
evolving and refining itself for more modern use cases.&lt;/p&gt;
&lt;p&gt;As a final reflection the &quot;correct&quot; method will always depend on your goals.
Remember that these tools are not exclusive to code editors like glyphide. They
are the fundamental base for building secure plugin systems like Figma does, and
currently thanks to the fact that many AI tools need to test generated code in a
secure environment to validate its functionality. This is driving a new wave of
engines designed for this purpose.&lt;/p&gt;
&lt;h2&gt;references&lt;/h2&gt;
&lt;p&gt;Resources that have helped me in the past and now to evaluate this topic and
experiment with different methods of execution.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.figma.com/blog/how-we-built-the-figma-plugin-system/&quot;&gt;how we built the figma plugin system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/quezo/post/improving-infinite-loop-detection&quot;&gt;Improving infinite loop detection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://krasimirtsonev.com/blog/article/build-your-own-interactive-javascript-playground&quot;&gt;Build your own interactive javascript playground&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://snyk.io/articles/javascript-security/&quot;&gt;JavaScript security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/alexgriss/the-architecture-of-browser-sandboxes-a-deep-dive-into-javascript-code-isolation-1dnj&quot;&gt;The architecture of browser sandbox: A deep dive into javascript code isolation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://healeycodes.com/sandboxing-javascript-code&quot;&gt;Sandboxing javascript code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tc39/proposal-shadowrealm/blob/main/explainer.md#Security&quot;&gt;ShadowRealm proposal explainer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=31966374&quot;&gt;Ducktape in HN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/35208161/is-it-safe-to-have-sandbox-allow-scripts-allow-popups-allow-same-origin-on-if&quot;&gt;question about iframe sandbox properties in stackoverflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dropbox.tech/security/csp-the-unexpected-eval&quot;&gt;CSP The unexpected eval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/sandboxed-iframes&quot;&gt;Sandboxed iframes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://portswigger.net/blog/dom-invader-and-the-case-of-direct-eval-vs-indirect-eval&quot;&gt;DOM invader and the case of direct eval vs indirect eval&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2026.01.31:&lt;/strong&gt; fixed spelling errors and explicitly marked the libraries that
I have not used.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2026.08.04:&lt;/strong&gt; added a note about the Glyphide version 3 architecture change.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><category>javascript</category><category>browser</category><category>glyphide</category><author>34664891+Pkcarreno@users.noreply.github.com (pk)</author><source url="https://pkcarreno.com/journal">journals</source></item></channel></rss>