Skip to content

UDF security and sandbox hardening

For the complete documentation index see: 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 (UDF filename path traversal).
  • An opt-in Lua sandbox hardening mode, enabled by setting 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 (Lua UDF sandbox escape).

For coordinated disclosure details, CVE status, affected versions, and patch release numbers, see 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
  • 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.

Threat model

Controlling who can register and execute UDFs is part of your defense. In clusters with role-based access control (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 before production deployment. The 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 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 before enabling it. See AS-2026-002 for the underlying vulnerability and fixed release lines.

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

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 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

OperationDefault mode (allow-unsafe-lua=true)Hardened mode (allow-unsafe-lua=false)
Register a foo.lua Lua source UDFacceptedaccepted
Register foo.LUA or any mixed-case variantacceptedrejected with error=unsafe_lua_disabled
Register a foo.so native moduleacceptedrejected with error=unsafe_lua_disabled
Register a precompiled Lua bytecode UDFacceptedrejected at registration (compile error)
Call os.time() inside a UDFallowedruntime error
Call os.execute() or io.popen() inside a UDFruntime errorruntime error

See also

Feedback

Was this page helpful?

What type of feedback are you giving?

What would you like us to know?

+Capture screenshot

Can we reach out to you?