Arango logo

Server security options

You can harden an ArangoDB server by restricting APIs, limit what can be accessed in JavaScript contexts, and disable unused features

arangod provides a variety of options to make a setup more secure. Administrators can use these options to limit access to certain ArangoDB server functionality as well as preventing the leakage of information about the environment that a server is running in.

Server hardening

If the --server.harden startup option is set to true and authentication is enabled, non-admin users are denied access to the following HTTP APIs:

  • /_admin/cluster/numberOfServers
  • /_admin/license
  • /_admin/metrics
  • /_admin/statistics-description
  • /_admin/statistics
  • /_admin/status
  • /_admin/system-report
  • /_admin/usage-metrics
  • /_api/engine/stats

Additionally, no version details are revealed by the version HTTP API at /_api/version.

The default value for this option is false.

API availability and access

Certain administrative endpoints can be restricted with startup options. Some only let you control the availability of API endpoints while others let you specify the access permissions and required level of authentication, or both. Disabling APIs you don’t use and increasing the access restriction help to reduce the attack surface.

JavaScript security options

arangod has several options that allow you to make your installation more secure when it comes to running application code in it. Below you find an overview of the relevant options.

Allowlists and denylists

Several options exist to restrict JavaScript application code functionality to just certain allowed subsets. Which subset of functionality is available can be controlled via “denylisting” and “allowlisting” access to individual components.

The set theory for these lists works as follow:

  • No allowlist or denylist is specified:
    Everything is allowed in versions up to ArangoDB v3.12.8. From v3.12.9 onward, access to the respective resources is disallowed by default in arangod. In arangosh, everything remains allowed by default. The shell runs client-side and is under the control of the user who starts it, so it doesn’t need to be as restrictive as the server.
  • Only a denylist is specified:
    Everything is allowed except a set of items matching the denylist.
  • Only an allowlist is specified:
    Everything is disallowed except the set of items matching the allowlist.
  • Both allowlist and denylist are specified:
    Everything is disallowed except the set of items matching the allowlist. From this allowed set, subsets can be forbidden again using the denylist.

Values for denylist and allowlist options need to be specified as ECMAScript regular expressions.

A pattern matches if it is found anywhere in a value, so it can match more than you intend. To restrict a pattern to exact matches:

  • Anchor it with ^(...) to only match the prefix, or ^(...)$ to match the whole value.
  • Escape characters with a special meaning, such as the dot: use \. for a literal dot, which otherwise matches any character.

For example, use ^http://example\.com/ instead of example.com for validating request URLs and ^/etc/issue$ instead of /etc/issue for specific file paths.

Each option can be used multiple times. When specifying more than one pattern, these patterns are combined with a logical or to the actual pattern ArangoDB uses.

These patterns and how they are applied can be observed in the arangod or arangosh log output by enabling --log.level security=debug.

Options for allowlisting and denylisting

The following options are available for allowlisting and denylisting access to dedicated functionality for application code:

  • --javascript.startup-options-[allowlist|denylist]:
    These options control which startup options are exposed to JavaScript code.

  • --javascript.environment-variables-[allowlist|denylist]:
    These options control which environment variables are exposed to JavaScript code.

  • --javascript.files-[allowlist|denylist]:
    These options control which filesystem paths can be accessed from JavaScript code.

  • --javascript.endpoints-[allowlist|denylist]:
    These options control which endpoints can be used from within the @arangodb/request JavaScript module.

Startup option access

Access to startup option settings can be restricted for JavaScript code to hide sensitive information that may be present in the values of the options.

The regular expression matching is case-sensitive.

Example:

--javascript.startup-options-allowlist "^server\."
--javascript.startup-options-allowlist "^log\."
--javascript.startup-options-denylist "^javascript\."
--javascript.startup-options-denylist "^endpoint$"

These sets are resolved internally to the following regular expressions:

--javascript.startup-options-allowlist = "^server\.|^log\."
--javascript.startup-options-denylist = "^javascript\.|endpoint"

Invoking arangosh with these options hides the denied command-line options from the output of the following method:

require('internal').options()

An exception is thrown when trying to access items that are masked in the same way as if they wouldn’t exist.

Environment variable access

Access to environment variables can be restricted for JavaScript code to hide sensitive information that may be stored in environment variables.

The regular expression matching is case-sensitive.

Example:

--javascript.environment-variables-allowlist "^ARANGO_"
--javascript.environment-variables-denylist "PASSWORD"

This allows JavaScript code to only see environment variables that start with ARANGO_, except if they contain PASSWORD. It excludes the variables PATH and ARANGO_ROOT_PASSWORD for instance.

PASSWORD won’t exclude environment variables that include password. You may use [Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd] for case-insensitive matching.

You can test the allow-/denylisting in arangosh, here using the ArangoDB 3.12 container image:

docker run --rm -e ARANGO_ROOT_PASSWORD="secret" arangodb:3.12 \
  arangosh --javascript.execute-string "print(process.env)"
{
  "HOSTNAME" : "0aea68ec522d",
  "SHLVL" : "1",
  "HOME" : "/root",
  "ARANGO_ROOT_PASSWORD" : "secret",
  "ARANGO_VERSION" : "3.12.8",
  "PATH" : "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
  "PWD" : "/",
  "GLIBCXX_FORCE_NEW" : "1",
  "ICU_DATA_LEGACY" : "/usr/share/arangodb3/",
  "ICU_DATA" : "/usr/share/arangodb3/"
}
docker run --rm -e ARANGO_ROOT_PASSWORD="secret" arangodb:3.12 \
  arangosh --javascript.execute-string "print(process.env)" \
  --javascript.environment-variables-allowlist "^ARANGO_" \
  --javascript.environment-variables-denylist "PASSWORD"
...
[Object {
  "ARANGO_VERSION" : "3.12.8"
}]

File access

Access to directories and files from JavaScript operations can be restricted using an allowlist via the --javascript.files-allowlist startup option and, from v3.12.10 onward, a denylist via the --javascript.files-denylist startup option. Any files or directories not matching the allowlist are inaccessible from JavaScript filesystem functions, and the denylist can forbid subsets of the allowed paths again.

The regular expression matching is case-insensitive.

Example:

--javascript.files-allowlist "^/etc/required/"
--javascript.files-allowlist "^/etc/mtab/"
--javascript.files-allowlist "^/etc/issue$"
--javascript.files-denylist "^/etc/required/secrets/"

The file /etc/issue can be accessed and all files in the directories /etc/required and /etc/mtab plus their subdirectories are accessible, except the files in /etc/required/secrets which are denied again. Access to files in any other directories is disallowed from JavaScript operations, with the following exceptions:

  • Temporary directory:
    JavaScript code is given access to this directory for storing temporary files. The temporary directory location can be specified explicitly via the --temp.path startup option. If the option is not specified, ArangoDB automatically use a subdirectory of the system’s temporary directory.

  • Bundled JavaScript code, shipped with arangod and arangosh:
    Files in this directory and its subdirectories are readable for JavaScript code running in arangosh. The exact path can be specified with the --javascript.startup-directory startup option.

URL access

Access to external HTTP resources can be restricted for JavaScript code.

Filtering is done against the full request URL as used in the JavaScript code, including the protocol, hostname/IP address, port, path, query parameters, and fragment identifier (e.g. http://host:port/path/?query=1#anchor).

The regular expression matching is case-insensitive.

Example:

--javascript.endpoints-allowlist "https?://(www\.)?arangodb\.org(:80|443)?/"
--javascript.endpoints-denylist "https?://(www\.)?arangodb\.org(:80|443)?/admin"

This allows requests to arangodb.org and www.arangodb.org over the HTTP and HTTPS protocols, using any paths (and query parameters) except paths with the prefix /admin.

Keep in mind that these startup options are treated as regular expressions. Certain characters have special meaning (e.g. .) that may require escaping (\.) and the expression only needs to match a substring (anywhere in the request URL) by default.

It is recommended to fully specify URLs and to use a leading ^ and potentially a trailing $ to ensure that no other than the intended URLs are matched.

To allow requests via HTTP and HTTPS to the host arangodb.org, you should use ^https?://arangodb\.org(:80|:443)?/ as the regular expression for the --javascript.endpoints-allowlist startup option. It only matches the intended URLs, that is any request path with arangodb.org as the host, with or without explicit mention of the HTTP/HTTPS default port, and not accidentally matching subdomains of third-parties (like http://arangodb.org.evil.domain) due to the slash after the domain/port:

  • http://arangodb.org/
  • http://arangodb.org/folder/file.html
  • http://arangodb.org/api?query=1&arg=2
  • http://arangodb.org:80/
  • http://arangodb.org:80/folder/file.html
  • http://arangodb.org:80/api?query=1&arg=2
  • https://arangodb.org/
  • https://arangodb.org/folder/file.html
  • https://arangodb.org/api?query=1&arg=2
  • https://arangodb.org:443/
  • https://arangodb.org:443/folder/file.html
  • https://arangodb.org:443/api?query=1&arg=2
  • etc.

You should never use something like arangodb.org as regular expression for the allowlist because it matches any request URL that contains arangodb followed by any character and org anywhere in the URL, including the path and query parameters. This most likely allows access to unintended URLs:

  • http://arangodb.org/ ✅
  • http://arangodb.org/folder/file.html ✅
  • https://arangodb.org/ ✅
  • https://arangodb.org:12345/ ❓
  • ftp://arangodb.org ❓
  • https://subdomain.arangodb.organic/ ⚠️
  • https://arangodb-org.evil.domain/ ⚠️
  • https://evil.domain/path/?query=arangodb+org ⚠️
  • etc.

An unescaped . represents any character. For a literal dot, use \..

You can restrict the access to specific protocols, even though http:// and https:// are the only ones supported by the request module.

Specifying http://arangodb\.org still matches more URLs than intended, namely any request URL that contains http://arangodb.org anywhere:

  • http://arangodb.org/ ✅
  • http://arangodb.org:12345/ ❓
  • http://arangodb.organic/ ⚠️
  • http://arangodb.org.evil.domain/ ⚠️
  • http://evil.domain/path/?query=http://arangodb.org ⚠️
  • etc.

You should anchor regular expressions for the allowlist to the beginning of the request URL with a leading ^. You can also anchor it to the end with a trailing $, but this may limit it too much.

Specifying ^http://arangodb\.org$ doesn’t match any request URL because the path in an HTTP request cannot be empty, and the regular expression doesn’t match http://arangodb.org/ (with / as the path).

Specifying ^http://arangodb\.org/$ only matches http://arangodb.org/, that is the root path. You are able to access the homepage for this host, but no other pages like http://arangodb.org/folder/file.html. Despite port 80 being the default HTTP port, it also doesn’t match requests to http://arangodb.org:80/ with an explicitly stated port. Conversely, specifying ^http://arangodb\.org:80/$ matches http://arangodb.org:80/ with an explicit port in the request URL but not http://arangodb.org/ with the port left out.

You can make the port optional like ^http://arangodb\.org(:80)?/$. However, the trailing $ restricts it to the root path and there cannot be any query parameters in the URL. This means http://arangodb.org/folder/file.html and http://arangodb.org/?query=1&arg=2 don’t match. To safely allow any path using arangodb.org as the host, you can use ^http://arangodb\.org(:80)?/. Note that there is no trailing $ for anchoring to the end of the request URL. However, a slash is required after the hostname (arangodb.org) respectively after the port (:80). Don’t forget the / as this prevents URLs like http://arangodb.org.evil.domain from accidentally matching the regular expression.

You may restrict access to specific subpaths with a regular expression like ^http://arangodb\.org(:80)?/(folder/|api). It matches request URLs like http://arangodb.org/folder/file.html and http://arangodb.org:80/api?query=1&arg=2 but not http://arangodb.org/foldError/ or http://arangodb.org:80/admin/api.

You can test the allow-/denylisting in arangosh as follows:

arangosh --javascript.endpoints-allowlist "^https://arangodb\.org(:443)?/"

127.0.0.1:8529@_system> require('internal').download('http://arangodb.org/file.zip')
JavaScript exception: ArangoError 11: not allowed to connect to this URL: http://arangodb.org/file.zip
...

127.0.0.1:8529@_system> require('internal').download('https://arangodb.org/file.zip')
<request permitted by allowlist>
Startup options may require additional escaping in your command line. For examples, dollar symbols and backslashes need to be escaped in most Linux shells (\$, \\) unless the entire string is wrapped in single quotes ('http://arangodb\.org$' instead of http://arangodb\\.org\$).

Additional JavaScript security options

In addition to the allowlisting and denylisting security options, the following extra options are available for locking down JavaScript access to certain functionality:

  • --javascript.allow-port-testing: If set to true, this option enables the testPort JavaScript function in the internal module. The default value is false.

  • --javascript.allow-external-process-control: If set to true, this option allows the execution and control of external processes from JavaScript code via functions from the internal module:

    • executeExternal
    • executeExternalAndWait
    • getExternalSpawned
    • killExternal
    • suspendExternal
    • continueExternal
    • statusExternal
  • --javascript.harden: If set to true, this setting deactivates the following JavaScript functions from the internal module, which may leak information about the environment:

    • getPid()
    • logLevel()

    The default value is false.

  • --javascript.tasks: You can set this option to false to turn off JavaScript tasks. It disallows the execution of user-defined JavaScript code on the server inside of periodic and one-off tasks.

  • --javascript.transactions: You can set this option to false to turn off JavaScript Transactions. It disallows the execution of user-defined JavaScript code on the server inside of JavaScript Transactions.

  • --javascript.user-defined-functions: You can set this option to false to turn off user-defined functions (UDFs). It disallows the execution of user-defined JavaScript code on the server inside of user-defined AQL functions (introduced in v3.10.4).

Security options for managing Foxx applications

The following options are available for controlling the installation of Foxx applications in an ArangoDB server:

  • --foxx.enable (introduced in v3.10.5): If set to false, this option disables access to any user-defined Foxx apps. Accessing the URL of any (existing or potentially existing) Foxx app produces an HTTP 403 Forbidden error with this setting. ArangoDB’s built-in web interface and all built-in REST APIs remain accessible, except the Foxx service management API, which makes it impossible to install and uninstall Foxx applications. Setting the option to false also deactivates the Services section in the web interface. The default value is true, meaning that Foxx apps can be accessed.

  • --foxx.api: If set to false, this option disables the Foxx management API, which will make it impossible to install and uninstall Foxx applications. Setting the option to false will also deactivate the “Services” section in the web interface. The default value is true, meaning that Foxx apps can be installed and uninstalled.

  • --foxx.store: If set to false, this option disables the Foxx app store in ArangoDB’s web interface, which will also prevent ArangoDB and its web interface from making calls to the main Foxx application Github repository at github.com/arangodb/foxx-apps . The default value is true.

  • --foxx.allow-install-from-remote: When set to false, this option prevents installation of Foxx apps from any remote source other than GitHub and deactivates the Remote tab in the Services section of the web interface. Installing apps from Github and/or zip files is still possible with this setting, but any other remote sources are blocked. When set to true, installing Foxx apps from other remote sources via URLs is allowed. The default value is false.