Skip to content

Fetch in Guest System

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:

  • If it can be restricted, it should be restricted.
  • If it can be avoided, it should be avoided.
  • If possible, the host system should have control and should only provide the needed information.
  • Consider runtime validation for inputs and outputs.

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

typescript
import { type SandboxOptions, loadQuickJs } 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 { runSandboxed } = await loadQuickJs()

const options:SandboxOptions = {
  allowFetch: false,
  env: {
    getExternalData: getData,
  },
}

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

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

const result = await runSandboxed(async ({ evalCode }) => evalCode(code, undefined, options), options)

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:

OptionTypeDescriptionDefault Value
fsIFsThe virtual file system of the sandbox (excludes node_modules)undefined
allowedHostsstring[]List of allowed hosts. If set, only these hosts are allowed to callundefined
allowedProtocolsstring[]List of allowed protocols. If set, only these protocols are allowed to call['http:', 'https:']
disallowedHostsstring[]List of disallowed hosts.['localhost', '127.0.0.1']
timeoutnumberTimeout for fetch requests in milliseconds5000 (5 seconds)
corsCheckbooleanFlag to enable CORS policy checkfalse
allowedCorsOriginsstring[]List of allowed CORS origins['*']
rateLimitPointsnumberNumber of requests allowed in the specified duration10
rateLimitDurationnumberDuration in seconds for the rate limit1

Features

Rate Limiting

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

  • Options:
    • rateLimitPoints: Number of requests allowed.
    • rateLimitDuration: Duration in seconds for the rate limit.

Protocol and Host Restrictions

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

  • Options:
    • allowedHosts: List of allowed hosts.
    • disallowedHosts: List of disallowed hosts.
    • allowedProtocols: List of allowed protocols.

Timeout Management

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

  • Options:
    • timeout: Timeout for fetch requests in milliseconds.

CORS Policy Enforcement

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

  • Options:
    • corsCheck: Flag to enable CORS policy check.
    • allowedCorsOrigins: List of allowed CORS origins.

Virtual File System Support

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

  • Options:
    • fs: The virtual file system of the sandbox.