---
title: "UDF security and sandbox hardening"
description: "Aerospike UDF filename validation rules and the optional Lua sandbox hardening switch."
---

# UDF security and sandbox hardening

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

This page describes two UDF security controls available in Aerospike Database 8.1.2.2, 8.0.0.17, 7.2.0.19, 7.1.0.25 and later:

-   An **always-on filename allowlist** that constrains valid UDF module names. This control applies automatically on upgrade; no configuration change is required. It addresses [AS-2026-001](https://aerospike.com/docs/database/release/security-bulletins#as-2026-001) (UDF filename path traversal).
-   An **opt-in Lua sandbox hardening** mode, enabled by setting [`mod-lua.allow-unsafe-lua`](https://aerospike.com/docs/database/reference/config#mod-lua__allow-unsafe-lua) to `false`, that removes risky Lua globals and disables non-Lua UDF formats. Opting in requires auditing your registered UDFs first. It mitigates [AS-2026-002](https://aerospike.com/docs/database/release/security-bulletins#as-2026-002) (Lua UDF sandbox escape).

For coordinated disclosure details, CVE status, affected versions, and patch release numbers, see [Security bulletins](https://aerospike.com/docs/database/release/security-bulletins).

## Applies to

-   Product: Aerospike Database 8.1.2.2, 8.0.0.17, 7.2.0.19, 7.1.0.25 and later

## Audience

Operators and developers who register, deploy, or audit UDF modules.

## Prerequisites

-   Familiarity with [managing UDFs](https://aerospike.com/docs/database/advanced/udf/managing)
-   For hardened mode: a staging cluster where you can test UDF compatibility before enabling the option in production

## Outcome

After reading this page, you can validate module names against the allowlist, decide whether to enable hardened mode, and audit registered UDFs against the [migration checklist](#migration-checklist-before-opting-in).

## Threat model

Controlling who can register and execute UDFs is part of your defense. In clusters with [role-based access control (RBAC)](https://aerospike.com/docs/database/manage/security/rbac) enabled:

-   **Registering or removing UDFs** requires the `udf-admin` privilege (also included in `data-admin` and `sys-admin`).
-   **Executing UDFs** requires the `read-write-udf` privilege.

Upgrade to 8.1.2.2, 8.0.0.17, 7.2.0.19, 7.1.0.25 or later to get the filename allowlist regardless of RBAC settings. We recommend enabling hardened mode after auditing your registered UDFs.

Clusters with security disabled allow unauthenticated UDF registration and execution. Treat network exposure as high risk, restrict access to trusted networks, and enable [access control](https://aerospike.com/docs/database/manage/security/rbac) before production deployment. The [Security bulletins](https://aerospike.com/docs/database/release/security-bulletins) describe the privilege and exposure assumptions for the disclosed UDF vulnerabilities.

## Filename allowlist (always on)

The server enforces a fixed allowlist on every UDF module name, including the extension. Non-conforming names are rejected. Hardened mode adds separate format rules on top of this check—for example, rejecting `.so` modules and mixed-case `.lua` extensions even when the name otherwise matches the allowlist.

Accepted names:

-   Use only ASCII letters, digits, and the characters `.`, `_`, `-`, and `$` (`[A-Za-z0-9._$-]`).
-   Are non-empty.
-   Do not begin with `.`.
-   Do not contain the substring `..` anywhere.

Rejections return `error=invalid_filename` to the client.

### What this means for module naming

Most deployments are unaffected: typical module names like `my_module.lua`, `aggregator.lua`, or `audit-2024.lua` pass without change. The following narrow profiles are affected:

-   **Non-ASCII module names** (accented letters, CJK characters, emoji, and so on) are no longer accepted. Affected modules cannot be registered, fetched, or removed after upgrade.
-   **Module names with spaces, `+`, `:`, or other punctuation** are rejected for the same reason.

### Cleanup for entries with newly invalid names

After upgrade, any pre-existing UDF whose name doesn’t conform to the new rules is hidden from `udf-list`, and a warning about it is written to the server log. The on-disk file (if any) remains in the configured UDF directory as an orphan.

You cannot clean these orphans up through a normal UDF remove, because remove applies the same allowlist. To remove them, delete the file directly from the [`mod-lua.user-path`](https://aerospike.com/docs/database/reference/config#mod-lua__user-path) directory on each node, or contact support. Orphan files do not affect normal cluster operation; cleanup can happen at your convenience.

## Lua sandbox hardening (opt-in)

Setting `allow-unsafe-lua=false` is a breaking change for any UDF that uses `os.*`, `io.*`, `debug.*`, `load*`, `package.loadlib`, native `.so` modules, or precompiled Lua bytecode. Audit your registered UDFs against the [migration checklist](#migration-checklist-before-opting-in) before enabling it. See [AS-2026-002](https://aerospike.com/docs/database/release/security-bulletins#as-2026-002) for the underlying vulnerability and fixed release lines.

The `mod-lua` configuration context accepts a new boolean option:

```plaintext
mod-lua {

    allow-unsafe-lua false   # default: true

}
```

The default is `true` so that existing deployments see no behavior change on upgrade. When an operator sets the option to `false`, the server applies additional restrictions to every UDF.

The setting is static, so changes take effect after a server restart. During a rolling restart, the cluster temporarily contains a mix of nodes in default and hardened modes; register or test UDFs only after every node has restarted and agreed on the setting.

See [`mod-lua.allow-unsafe-lua`](https://aerospike.com/docs/database/reference/config#mod-lua__allow-unsafe-lua) for the configuration reference.

### What hardened mode changes

When `allow-unsafe-lua=false`, the server enforces the following restrictions:

-   **Removes Lua globals**: `os`, `io`, `debug`, `dofile`, `loadfile`, `load`, and `loadstring` become unavailable. `require("os")` and similar workarounds cannot recover them.
-   **Removes package internals**: `package.searchpath`, `package.loadlib`, and `package.cpath` are not available, closing the path that arbitrary C libraries could otherwise be loaded through.
-   **Blocks non-Lua UDFs**: only Lua source UDFs can be registered. Native shared-object (`.so`) modules are rejected.
-   **Blocks bytecode UDFs**: only text-format Lua source is accepted. Precompiled bytecode UDFs are rejected at registration with a compile error.
-   **Requires the lowercase `.lua` extension** at registration. Other extensions, including uppercase or mixed-case variants of `.lua`, are rejected with `error=unsafe_lua_disabled`.

When `allow-unsafe-lua=true`, the server logs a startup warning advising operators to consider hardening.

### Implications for `os.*` functions

Earlier versions of these docs noted that four functions from the Lua `os` library (`os.clock()`, `os.date()`, `os.difftime()`, and `os.time()`) were permitted in UDFs. Under hardened mode the entire `os` table is removed; those four functions are no longer available when `allow-unsafe-lua=false`. UDFs that depend on them must be updated before opting in.

The four functions remain available under the default `allow-unsafe-lua=true` setting.

### Migration checklist before opting in

Before setting `allow-unsafe-lua=false` in production, audit your registered UDFs for any of the following:

-   Calls to `os.*`, including `os.time`, `os.date`, `os.clock`, and `os.difftime`.
-   Calls to `io.*`, `debug.*`, `dofile`, `loadfile`, `load`, `loadstring`, `package.loadlib`, or `package.searchpath`.
-   Native `.so` UDF modules.
-   Precompiled Lua bytecode UDFs.
-   UDF filenames with uppercase or mixed-case extensions.

If any of these are present, update the UDFs or remove the dependency before enabling hardened mode. Hardened mode is intended for deployments that have audited their UDFs and confirmed compatibility. Validate the change in a staging cluster before flipping it in production.

Aerospike’s bundled UDF helper libraries (`as.lua`, `stream_ops.lua`, and `aerospike.lua`) do not use any of the removed functions.

To revert hardened mode, set `allow-unsafe-lua true` in the `mod-lua` stanza and restart each node.

### Behavior summary

| Operation | Default mode (`allow-unsafe-lua=true`) | Hardened mode (`allow-unsafe-lua=false`) |
| --- | --- | --- |
| Register a `foo.lua` Lua source UDF | accepted | accepted |
| Register `foo.LUA` or any mixed-case variant | accepted | rejected with `error=unsafe_lua_disabled` |
| Register a `foo.so` native module | accepted | rejected with `error=unsafe_lua_disabled` |
| Register a precompiled Lua bytecode UDF | accepted | rejected at registration (compile error) |
| Call `os.time()` inside a UDF | allowed | runtime error |
| Call `os.execute()` or `io.popen()` inside a UDF | runtime error | runtime error |

## See also

-   [Security bulletins](https://aerospike.com/docs/database/release/security-bulletins)
-   [Configure access control](https://aerospike.com/docs/database/manage/security/rbac)
-   [Configuration reference: `mod-lua.allow-unsafe-lua`](https://aerospike.com/docs/database/reference/config#mod-lua__allow-unsafe-lua)
-   [Configuration reference: `mod-lua.user-path`](https://aerospike.com/docs/database/reference/config#mod-lua__user-path)
-   [Developing UDF Modules](https://aerospike.com/docs/database/advanced/udf/modules)
-   [Known limitations](https://aerospike.com/docs/database/advanced/udf/limitations)