Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/main/java/dev/amble/lib/script/AbstractScriptManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import dev.amble.lib.AmbleKit;
import dev.amble.lib.script.lua.LuaBinder;
import dev.amble.lib.script.lua.MinecraftData;
import dev.amble.lib.script.lua.SandboxedGlobals;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.jse.JsePlatform;

import java.io.InputStreamReader;
import java.util.HashMap;
Expand Down Expand Up @@ -72,7 +72,8 @@ public LuaScript load(Identifier id, ResourceManager manager) {
return cache.computeIfAbsent(id, key -> {
try {
Resource res = manager.getResource(key).orElseThrow();
Globals globals = JsePlatform.standardGlobals();
// Use sandboxed globals to prevent access to dangerous APIs like luajava
Globals globals = SandboxedGlobals.create();

// Create and cache the minecraft data for this script
MinecraftData data = createMinecraftData();
Expand All @@ -89,7 +90,7 @@ public LuaScript load(Identifier id, ResourceManager manager) {
);
chunk.call();

LuaScript script = new LuaScript(globals);
LuaScript script = new LuaScript(globals);

// Call onRegister when script is first loaded into the manager
if (script.onRegister() != null && !script.onRegister().isnil()) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/dev/amble/lib/script/lua/LuaBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ public Varargs invoke(Varargs args) {
}

meta.set("__index", index);

return meta;
}
}
79 changes: 79 additions & 0 deletions src/main/java/dev/amble/lib/script/lua/SandboxedGlobals.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package dev.amble.lib.script.lua;

import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.BaseLib;
import org.luaj.vm2.lib.Bit32Lib;
import org.luaj.vm2.lib.StringLib;
import org.luaj.vm2.lib.TableLib;
import org.luaj.vm2.lib.jse.JseMathLib;

/**
* Creates a sandboxed Lua environment that prevents access to dangerous APIs.
* <p>
* This specifically excludes:
* <ul>
* <li>luajava - Prevents arbitrary Java class access and code execution</li>
* <li>os library - Prevents system command execution and file operations</li>
* <li>io library - Prevents file system access</li>
* <li>debug library - Prevents environment manipulation and introspection attacks</li>
* <li>package library - Prevents loading modules from disk</li>
* <li>load/loadfile/dofile - Prevents loading code from files</li>
* </ul>
*/
public final class SandboxedGlobals {

private SandboxedGlobals() {
// Utility class
}

/**
* Creates a new sandboxed Lua globals environment.
* This environment is safe to use with untrusted scripts.
*
* @return A new sandboxed Globals instance
*/
public static Globals create() {
Globals globals = new Globals();

// Install safe base libraries only
// Using BaseLib instead of JseBaseLib to avoid any file system access
globals.load(new BaseLib()); // Basic functions (print, type, tostring, etc.)
globals.load(new Bit32Lib()); // Bit operations
globals.load(new TableLib()); // Table manipulation
globals.load(new StringLib()); // String manipulation
globals.load(new JseMathLib()); // Math functions

// NOTE: We intentionally do NOT load:
// - PackageLib (can search/load files from disk)
// - IoLib / JseIoLib (file system access)
// - OsLib / JseOsLib (system commands, file operations)
// - DebugLib (can manipulate environments)
// - LuajavaLib (arbitrary Java class access)

// Install the compiler so scripts can be loaded from strings
LoadState.install(globals);
LuaC.install(globals);

// Remove dangerous functions from base library
removeDangerousFunctions(globals);

return globals;
}

/**
* Removes dangerous functions that could be used to escape the sandbox.
*/
private static void removeDangerousFunctions(Globals globals) {
// Remove functions that can load code from files
globals.set("dofile", LuaValue.NIL); // Loads and executes files from disk
globals.set("loadfile", LuaValue.NIL); // Loads files from disk

// Remove load/loadstring to prevent any dynamic code execution
// This is the safest option as it prevents all forms of dynamic code loading
globals.set("load", LuaValue.NIL);
globals.set("loadstring", LuaValue.NIL);
}
}