# Capabilities

SurrealDB is secure by default and is suitable for all database use cases. It offers powerful features like scripting, functions or network access from within your SurrealQL queries.

Most powerful features — scripting, functions, network access — are disabled by default and must be explicitly enabled by an administrator per use case.

> [!IMPORTANT]
> Capabilities are configured per instance from **Instance settings** in [SurrealDB Studio](https://app.surrealdb.com). See [Configure an instance](/docs/manage/instances/configure.md) for the available settings.

When a query wants to use a capability that is not allowed, SurrealDB will reject it.

```surql title="Rejected Query"
http::get("https://www.surrealdb.com");

["Access to network target 'www.surrealdb.com:443' is not allowed"]
```

This rejection will also be logged in the SurrealDB server.

```bash title="Rejected Query Logging"
WARN surrealdb_core::ctx::context: Capabilities denied outgoing network connection attempt, target: 'www.surrealdb.com:443'
```

In production deployments, we recommend denying all capabilities by default and specifically allowing only those required.

```bash
surreal start --deny-all --allow-funcs "array, string, crypto::argon2, http::get" --allow-net api.example.com:443
```

You can learn more about best practices when using capabilities in our [Security Best Practices](/docs/learn/security/best-practices/security-best-practices.md#capabilities) guide.

## Priority

By default, all capabilities are denied unless allowed. Some few capabilities (e.g. functions) are allowed by default.

Capabilities can be configured globally (e.g. `--allow-all`, `--deny-all`), generally (e.g. `--allow-net`, `--deny-funcs`) or specifically (e.g. `--deny-net 192.168.1.1`, `--allow-funcs string::len`).
When capabilities are configured, the more specific capabilities prevail over the less specific. At the same level of specificity, denies always prevail over allows.

### Examples

Capabilities configured generally prevail over those defined globally:
- Running with `--deny-all --allow-scripting` will deny all capabilities except for scripting.
- Running with `--allow-all --deny-net` will allow all capabilities except for network.

Capabilities configured specifically prevail over those defined globally or generally:
- Running with `--deny-all --allow-net example.com` will deny all capabilities except network connections to `example.com`.
- Running with `--allow-all --deny-funcs http` will allow all capabilities except for calling functions of the `http` family.
- Running with `--deny-funcs --allow-funcs string::len` will deny all functions except for `string::len`.
- Running with `--allow-net --deny-net 10.0.0.0/8` will allow all network connections except to the `10.0.0.0/8` block.

Capabilities denied specifically prevail over those allowed specifically:
- Running with `--deny-funcs crypto --allow-funcs md5` will deny all functions of the `crypto` including `crypto::md5`.
- Running with `--allow-funcs crypto --deny-funcs md5` will allow all functions of the `crypto` family except for `crypto::md5`.

## Server versus client configuration

Capability flags on [`surreal start`](/docs/reference/cli/surrealdb-cli/commands/start.md) configure the **running database instance**. That is what enforces permissions when clients connect over HTTP, WebSocket, RPC, or [`surreal sql`](/docs/reference/cli/surrealdb-cli/commands/sql.md) to a remote endpoint.

[`surreal sql`](/docs/reference/cli/surrealdb-cli/commands/sql.md) accepts the same flags, but they apply differently:

| How you connect | Configure capabilities on |
| --- | --- |
| Remote server (`ws://`, `http://`, …) | **`surreal start`** (or server env vars) |
| Embedded storage (`memory`, `rocksdb://…`, …) | **`surreal sql`** |

When using a remote server, flags on `surreal sql` do **not** enable or disable execution-time checks such as [`eval::*`](/docs/reference/query-language/functions/database-functions/eval.md), arbitrary-query gates, or experimental features. They can still affect **REPL line parsing** before a query is sent.

See [Capabilities and remote connections](/docs/reference/cli/surrealdb-cli/commands/sql.md#capabilities-and-remote-connections) for detail.

## List

List of options for allowing capabilities:

<table>
    <thead>
        <tr>
            <th scope="col">Option</th>
            <th colspan="2" scope="col">Description</th>
            <th scope="col">Default</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td scope="row" data-label="Option">
                -A, --allow-all
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Allow all capabilities except for those more specifically denied like experimental features
            </td>
            <td scope="row" data-label="Default">
                False
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                -A, --allow-arbitrary-query
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Denies arbitrary queries to be used by user groups. Possible user groups are: 'guest', 'record', and 'system'.
            </td>
            <td scope="row" data-label="Default">
                False
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --allow-experimental
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Allow the usage of one or more experimental features. Possible values are `files`, `surrealism`, and `mutable_permissions`, separated by a comma. See <a href="/docs/reference/cli/surrealdb-cli/commands/start.md#experimental-capabilities">experimental capabilities</a> for which tag enables each feature. From 3.3.0 a server enables `mutable_permissions` on its own; name it in <code>--deny-experimental</code> to turn it off. (The legacy tag <code>gql</code> is still accepted for compatibility but is unused from 3.3.0 — GQL is on by default.)
            </td>
            <td scope="row" data-label="Default">
                None
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --allow-eval-query [&lt;target&gt;,...]
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Allow the <code>eval::surql</code> and <code>eval::gql</code> functions for certain user groups (<code>guest</code>, <code>record</code>, <code>system</code>). Denied for everyone by default, even under <code>--allow-all</code>. Cannot bypass <code>--deny-arbitrary-query</code> for the same subject. See <a href="#eval-queries">eval queries</a>.
            </td>
            <td scope="row" data-label="Default">
                None
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --allow-funcs [&lt;target&gt;,...]
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Allow execution of all functions except for functions that are specifically denied. Alternatively, you can provide a comma-separated list of function names to allow
            </td>
            <td scope="row" data-label="Default">
                None
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --allow-guests
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Allow non-authenticated users to execute queries when authentication is enabled
            </td>
            <td scope="row" data-label="Default">
                False
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --allow-net [&lt;target&gt;,...]
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Allow all outbound network access except for network targets that are specifically denied. Alternatively, you can provide a comma-separated list of network targets to allow
            </td>
            <td scope="row" data-label="Default">
                None
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --allow-scripting
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Allow execution of embedded scripting functions
            </td>
            <td scope="row" data-label="Default">
                False
            </td>
        </tr>
    </tbody>
</table>

List of options for denying capabilities:

<table>
    <thead>
        <tr>
            <th scope="col">Option</th>
            <th colspan="2" scope="col">Description</th>
            <th scope="col">Default</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td scope="row" data-label="Option">
                -D, --deny-all
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Deny all capabilities except for those more specifically allowed
            </td>
            <td scope="row" data-label="Default">
                False
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                -D, --deny-arbitrary-query
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Denies arbitrary queries from being used by user groups. Possible user groups are: 'guest', 'record', and 'system'
            </td>
            <td scope="row" data-label="Default">
                False
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --deny-eval-query [&lt;target&gt;,...]
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Deny the <code>eval::surql</code> and <code>eval::gql</code> functions for certain user groups (<code>guest</code>, <code>record</code>, <code>system</code>). Specifically denied groups prevail over allowed groups. See <a href="#eval-queries">eval queries</a>.
            </td>
            <td scope="row" data-label="Default">
                None
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --deny-funcs [&lt;target&gt;,...]
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Deny execution of all functions except for functions that are specifically allowed. Alternatively, you can provide a comma-separated list of function names to deny
            </td>
            <td scope="row" data-label="Default">
                None
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --deny-guests
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Deny non-authenticated users to execute queries when authentication is enabled
            </td>
            <td scope="row" data-label="Default">
                False
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --deny-net [&lt;target&gt;,...]
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Deny all outbound network access except for network targets that are specifically allowed. Alternatively, you can provide a comma-separated list of network targets to deny
            </td>
            <td scope="row" data-label="Default">
                None
            </td>
        </tr>
        <tr>
            <td scope="row" data-label="Option">
                --deny-scripting
            </td>
            <td colspan="2" scope="row" data-label="Description">
                Deny execution of embedded scripting functions
            </td>
            <td scope="row" data-label="Default">
                False
            </td>
        </tr>
    </tbody>
</table>

## Guest access

Guest access is used when you want to expose certain parts of a database to non-authenticated users. It's useful when you want to serve datasets publicly and still require authentication for the rest of the system.

Even when this capability is allowed, a guest user can only execute functions or data operations like SELECT, CREATE, etc, and only if the `PERMISSIONS` clause for the resource being used in the query allows it.

```surql
// Prepare tables with custom PERMISSIONS
test/test> DEFINE TABLE protected PERMISSIONS NONE;
test/test> DEFINE TABLE public PERMISSIONS FULL;

// When guest access is allowed
$ surreal start --allow-guests

test/test> CREATE public;
[{ id: public:uy0qzy31v4xox8vivrd4 }]

test/test> SELECT * FROM public;
[{ id: public:uy0qzy31v4xox8vivrd4 }]

test/test> CREATE protected;
[]

test/test> SELECT * FROM protected;
[]

// When guest access is denied
$ surreal start --deny-guests

test/test> CREATE public;
There was a problem with the database: There was a problem with the database: IAM error: Not enough permissions to perform this action

test/test> SELECT * FROM public;
There was a problem with the database: There was a problem with the database: IAM error: Not enough permissions to perform this action

test/test> CREATE protected;
There was a problem with the database: There was a problem with the database: IAM error: Not enough permissions to perform this action

test/test> SELECT * FROM protected;
There was a problem with the database: There was a problem with the database: IAM error: Not enough permissions to perform this action
```

## Functions

SurrealDB offers [built-in functions](/docs/reference/query-language/functions/database-functions/array.md) to perform common operations like string manipulation, math, etc. Users can also define [their own functions](/docs/reference/query-language/statements/define/function.md) with custom logic.

In certain environments, you may not want users to use specific functions (i.e. `http::*`) or execute any custom function at all. You can use the allow/deny lists to configure what functions are allowed and what functions are denied.

```bash
// Allow all functions except the http family and crypto::md5()
surreal start --allow-funcs --deny-funcs "http","crypto::md5"

// Allow certain custom functions only (all custom functions start with "fn::")
surreal start --allow-funcs "fn::shared_fn"
```

## Network

SurrealDB can make outbound network connections from [`http::*`](/docs/reference/query-language/functions/database-functions/http.md) functions and from JWKS fetches used by [JWT access methods](/docs/reference/query-language/statements/define/access/jwt.md#json-web-key-set-jwks). Use `--allow-net` and `--deny-net` to control which targets those connections may reach.

```bash
# Deny network access to localhost and private IPv4 ranges
surreal start --allow-net --deny-net "127.0.0.1","localhost","10.0.0.0/8","192.168.0.0/16","172.16.0.0/12"

# Allow access to an internal system on port 443 only
surreal start --allow-net internal.example.com:443

# Allow access to some private networks but not to others
surreal start --allow-net 10.0.0.0/16 --deny-net 10.10.0.0/24
```

SurrealDB resolves hostnames with DNS, then checks every resulting IP address against `--allow-net` and `--deny-net`. A hostname that resolves to an address listed in `--deny-net` is blocked.

Note that allowlisting a hostname alone is not enough when that name resolves to a private or special-use address (loopback, link-local, RFC1918 ranges, cloud metadata endpoints, etc.). SurrealDB blocks those addresses unless you also list the IP or CIDR in `--allow-net`, or you pass `--allow-net` with no target filter. This reduces SSRF risk from DNS rebinding or HTTP redirects into the local network.

Example for an in-cluster JWKS issuer whose service name resolves inside `10.0.0.0/8`:

```bash
surreal start --deny-all --allow-net idp.namespace.svc,10.0.0.0/8
```

> [!WARNING]
> SurrealDB does not perform reverse DNS lookups. A client can still reach an IP address directly even when a hostname that resolves to that IP is listed in `--deny-net`. This matters when network access is allowed by default (for example `--allow-net --deny-net www.example.com`) or when an IP is allowlisted while its hostname is denylisted (for example `--allow-net 203.0.113.10 --deny-net www.example.com`).

Deny by default: list only the `--allow-net` targets you need, and keep additional network controls in your infrastructure.

## Arbitrary queries

_(since v2.2.0)_

The `--allow-arbitrary-query` and `--deny-arbitrary-query` allows database administrators to allow or deny arbitrary quering by either guest, record or system users, or a combination of those. This capability settings affects the following:  [/sql endpoint](/docs/reference/rest-api/http-protocol.md#sql), [/key endpoints](/docs/reference/rest-api/http-protocol.md#get-table), [/graphql endpoint](/docs/reference/rest-api/http-protocol.md#graphql), [/gql endpoint](/docs/reference/rest-api/http-protocol.md#gql), the [Postgres wire protocol](/docs/reference/rest-api/postgres-protocol.md) listener, [RPC methods](/docs/reference/rest-api/rpc-protocol.md) `use`, `select`, `create`, `update`, `merge`, `patch`, `delete`, `relate`, `insert`, `insert_relation`, `query`, `gql`, and `graphql`, and the [`eval::*`](/docs/reference/query-language/functions/database-functions/eval.md) functions.

Endpoints that do not accept arbitrary queries such as [`/version`](/docs/reference/rest-api/http-protocol.md#version) and [authentication endpoints](/docs/reference/rest-api/http-protocol.md#signin) are not affected.

The `--deny-arbitrary-query` flag is often preceded with a [`DEFINE API`](/docs/reference/query-language/statements/define/api.md) statement to set up certain endpoints that users can use to access database resources in place of arbitrary queries.

## Eval queries

_(since v3.2.0)_

The [`eval::surql`](/docs/reference/query-language/functions/database-functions/eval.md) and [`eval::gql`](/docs/reference/query-language/functions/database-functions/eval.md) functions evaluate query strings at runtime. They are controlled by **`--allow-eval-query`** and **`--deny-eval-query`**, with subject groups `guest`, `record`, and `system`.

Unlike most capabilities, **eval is denied for every subject by default**, including when you pass `--allow-all`. You must opt in explicitly:

```bash
surreal start --allow-eval-query
```

Arbitrary queries are **allowed by default** on the server, so you do not need `--allow-arbitrary-query` for eval unless you have restricted arbitrary queries (for example with `--deny-arbitrary-query` or `--deny-all`). If a subject is denied arbitrary queries — a common pattern alongside [`DEFINE API`](/docs/reference/query-language/statements/define/api.md) — **`eval` is denied for that subject too**, even when `--allow-eval-query` includes them. `eval` cannot bypass arbitrary-query lockdown.

Deny rules at the same specificity prevail over allow rules. A record user calling an owner-defined function that invokes `eval` is still checked as `record` — auth limiting never escalates the subject.

Configure `--allow-eval-query` on **`surreal start`** when clients connect to a remote instance. It is not required on `surreal sql` for remote connections — only for [embedded REPL sessions](/docs/reference/cli/surrealdb-cli/commands/sql.md#capabilities-and-remote-connections).

`eval::gql` does not need an experimental capability from **3.3.0** (on **3.2.x**, also allow `gql`). See [Eval functions](/docs/reference/query-language/functions/database-functions/eval.md) and [Representations and codecs](/docs/learn/querying/concepts-and-guides/representations-and-codecs.md).
