Skip to the content.

Allowing the guest system inside a sandbox to connect to the outside world is potentially risky. Therefore, the usage should be restricted as much as possible.

Consider Alternatives

Balancing technical needs, possibilities, security, and implementation overhead highly depends on the individual application.

As general rules:

A common example is calling an API. A better alternative is to create a helper function provided to the host instead of providing full fetch functionality to the guest system, especially in cases where the API is protected and/or the creator of the executed code is “some user.”

Simple Example

import { quickJS } from '@sebastianwessel/quickjs'
import { z } from 'zod'

const getData = async (input: string) => {
  try {
    // Do not trust the client system - validate input
    const id = z.string().parse(input)

    const result = await fetch('https://example.com/api/' + id, {
      // Secrets are only available on the host system
      headers: { Authentication: 'Bearer MY_SECRET_ONLY_ON_HOST' },
    })

    if (result.ok) {
      const payload = await result.json()

      // Validate & strip out any data that is not required
      const payloadValidationSchema = z.object({
        myValue: z.string(),
      })

      return payloadValidationSchema.parse(payload)
    }
  } catch (_err) {
    // Do not expose host internal details
    throw new Error('Request failed')
  }
}

const { createRuntime } = await quickJS()

const { evalCode } = await createRuntime({
  allowFetch: false,
  env: {
    getExternalData: getData,
  },
})

const result = await evalCode(`
const fn = async ()=>{
  const data = await env.getExternalData('some-id')

  return data.myValue
}
  
export default await fn()
`)

console.log(result)

Default Adapter

The default fetch adapter, which is provided by default, has basic default settings to improve security. However, developers should not expect this default client to be secure and cover all potential issues.

The getDefaultFetchAdapter function provides a customizable fetch adapter with additional features such as rate limiting, protocol and host restrictions, virtual file system support, timeout management, and CORS policy enforcement. This adapter can be used to enhance the security and control of fetch requests in various applications.

Options

The getDefaultFetchAdapter function accepts an options object to configure its behavior. Below is a table describing the available options and their default values:

Option Type Description Default Value
fs IFs The virtual file system of the sandbox (excludes node_modules) undefined
allowedHosts string[] List of allowed hosts. If set, only these hosts are allowed to call undefined
allowedProtocols string[] List of allowed protocols. If set, only these protocols are allowed to call ['http:', 'https:']
disallowedHosts string[] List of disallowed hosts. ['localhost', '127.0.0.1']
timeout number Timeout for fetch requests in milliseconds 5000 (5 seconds)
corsCheck boolean Flag to enable CORS policy check false
allowedCorsOrigins string[] List of allowed CORS origins ['*']
rateLimitPoints number Number of requests allowed in the specified duration 10
rateLimitDuration number Duration in seconds for the rate limit 1

Features

Rate Limiting

The fetch adapter enforces rate limiting to control the number of requests allowed in a specified duration.

Protocol and Host Restrictions

The fetch adapter can restrict requests based on allowed and disallowed hosts and protocols.

Timeout Management

The fetch adapter supports setting a timeout for fetch requests to prevent long-running requests.

CORS Policy Enforcement

The fetch adapter can enforce CORS policies based on allowed origins.

Virtual File System Support

The fetch adapter can work with a virtual file system to handle file protocol requests.