Skip to content

Security ​

qzjs is an embeddable runtime for trusted script, not a sandbox for untrusted code. This page states the boundaries explicitly so you can reason about your deployment and report findings correctly.

Reporting a Vulnerability ​

Do not open a public GitHub issue for security vulnerabilities.

Report privately via GitHub Security Advisories. Include:

  • the affected version (commit hash or release tag),
  • a description of the issue and its impact,
  • steps to reproduce, or a proof of concept,
  • any known mitigations.

You should receive an acknowledgement within 7 days and a status update within 30 days. Once a fix is available we coordinate disclosure with you and credit you in the advisory unless you prefer to remain anonymous.

Supported Versions ​

Security fixes are applied to the latest release and the current master branch. Older releases are not back-ported.

Threat Model ​

In scope ​

Defects that let data cross a boundary the runtime itself draws, or that let unexpected input corrupt memory or crash the process:

  • the bytecode reader (JS_ReadObject) handling malformed or hostile bytecode,
  • the IPC envelope decoder and the HTTP/WS/HTTP2/protobuf parsers handling malformed input from a peer process or the network,
  • memory-safety defects reachable from script through the public API,
  • crypto correctness (crypto.subtle, TLS configuration, randomness).

If you find a way for untrusted input — network bytes, bytecode, IPC frames from an untrusted peer — to reach memory corruption, escape a parser boundary, or bypass an explicit validation, that is in scope.

Out of scope by design ​

Capabilities script already legitimately has. These are not escapes:

  • Filesystem — script can read and write any path the host process can. Path validation only rejects .. components; there is no root jail and no permission model. See fs.
  • Process spawning — script can spawn processes (pal.processSpawn → execv).
  • Environment — script can read the full environment via globalThis.env.
  • Host co-residence — script runs in-process with the host (THREAD backend) or in a sibling process (ISOLATED backend); neither is a security boundary against malicious script.
  • Network exposure — serve() binds 127.0.0.1 by default and has no authentication middleware. Passing hostname: '0.0.0.0' exposes it to the network — put your own authentication in front if you do that.

Deployment Guidance ​

Because the runtime trusts its script, the security of a qzjs deployment is the security of your host application's boundary:

  1. Treat script as first-party code. If any part of it comes from an untrusted source, do not run it in a qzjs runtime without your own confinement (a separate OS user, a container, a VM, or a seccomp policy).
  2. Do not expose serve() directly to the internet. It is a bare server. Bind to loopback and front it with a reverse proxy that terminates TLS and enforces authentication.
  3. Constrain what the process can reach. The filesystem, environment, and spawn capability are as broad as the host process's own privileges. Drop those privileges at the OS level if the workload does not need them.
  4. Prefer ISOLATED when isolation matters operationally. A crashing or wedged worker does not take down the main runtime, and the process boundary is cleaner for resource limits. It is still not a security boundary against malicious script.
  5. Verify TLS peers. The runtime performs SNI and certificate hostname verification on outbound TLS; a verification failure is fatal to that connection rather than silently ignored.
  6. Audit proxy configuration. fetch honors HTTP_PROXY / HTTPS_PROXY / NO_PROXY from the environment. An unsupported proxy scheme fails closed rather than bypassing the proxy silently — but any process able to set those variables can redirect outbound traffic.

Upstream Dependencies ​

qzjs vendors its dependencies as pinned git submodules under deps/, plus local patches (deps/*.patch).

Upstream quickjs-ng explicitly lists bytecode-reader hardening as out of scope for their project, so malformed-bytecode findings against the vendored reader belong here rather than upstream.

Report issues in a bundled dependency to us first so we can assess the impact on this runtime; we will also pass them upstream where appropriate.

See Also ​

  • Troubleshooting — symptom → cause → fix
  • FAQ — design questions that look like bugs
  • fs — the no-sandbox filesystem model
  • serve() — the unauthenticated HTTP server

MIT Licensed