CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-graalvm-polyglot--graalvm-sdk

GraalVM Polyglot API for multi-language runtime environments with host-guest interoperability and security controls.

Pending
Overview
Eval results
Files

security-access.mddocs/

Security and Access Control

GraalVM Polyglot API provides comprehensive security mechanisms to control access between host and guest languages. This includes host access policies, polyglot evaluation restrictions, sandboxing levels, and environment access controls.

Host Access Policies

HostAccess controls how guest languages can interact with host (Java) objects, providing fine-grained security policies from completely open access to strict sandboxing.

Predefined HostAccess Policies

public final class HostAccess {
    // Annotation-based access - only @Export members accessible
    public static final HostAccess EXPLICIT;
    
    // Scoped access with automatic resource cleanup
    public static final HostAccess SCOPED;
    
    // Full unrestricted access to all host objects
    public static final HostAccess ALL;
    
    // No host access allowed
    public static final HostAccess NONE;
    
    // Limited access suitable for constrained environments
    public static final HostAccess CONSTRAINED;
    
    // Method scoping enabled for enhanced isolation
    public static final HostAccess ISOLATED;
    
    // Strict restrictions for untrusted code execution
    public static final HostAccess UNTRUSTED;
}

Predefined Policy Examples:

// EXPLICIT: Only annotated members accessible
Context explicitContext = Context.newBuilder("js")
    .allowHostAccess(HostAccess.EXPLICIT)
    .build();

public class RestrictedAPI {
    @HostAccess.Export
    public String publicMethod() {
        return "This is accessible";
    }
    
    public String privateMethod() {
        return "This is NOT accessible";
    }
}

explicitContext.getBindings("js").putMember("api", new RestrictedAPI());
explicitContext.eval("js", "console.log(api.publicMethod())"); // Works
// explicitContext.eval("js", "api.privateMethod()"); // Would throw exception

// ALL: Full access (use with caution)
Context openContext = Context.newBuilder("js")
    .allowHostAccess(HostAccess.ALL)
    .build();

// CONSTRAINED: Limited access for sandboxed execution
Context constrainedContext = Context.newBuilder("js")
    .allowHostAccess(HostAccess.CONSTRAINED)
    .sandbox(SandboxPolicy.CONSTRAINED)
    .build();

Custom HostAccess Configuration

// Factory methods for custom configuration
public static HostAccess.Builder newBuilder();
public static HostAccess.Builder newBuilder(HostAccess conf);

The HostAccess.Builder provides extensive customization options:

public static final class HostAccess.Builder {
    // Access control methods
    public HostAccess.Builder allowPublicAccess(boolean enabled);
    public HostAccess.Builder allowAllImplementations(boolean enabled);
    public HostAccess.Builder allowAllClassImplementations(boolean enabled);
    public HostAccess.Builder allowArrayAccess(boolean enabled);
    public HostAccess.Builder allowListAccess(boolean enabled);
    public HostAccess.Builder allowBufferAccess(boolean enabled);
    public HostAccess.Builder allowIterableAccess(boolean enabled);
    public HostAccess.Builder allowIteratorAccess(boolean enabled);
    public HostAccess.Builder allowMapAccess(boolean enabled);
    
    // Annotation-based access
    public HostAccess.Builder allowAccessAnnotatedBy(Class<? extends Annotation> annotation);
    public HostAccess.Builder allowImplementationsAnnotatedBy(Class<? extends Annotation> annotation);
    
    // Method scoping and inheritance
    public HostAccess.Builder methodScoping(boolean enabled);
    public HostAccess.Builder allowAccessInheritance(boolean enabled);
    
    // Target type mappings
    public HostAccess.Builder targetTypeMapping(Class<?> sourceType, Class<?> targetType, Predicate<Object> accepts, Function<Object, Object> converter);
    public HostAccess.Builder targetTypeMapping(Class<?> sourceType, Class<?> targetType, Predicate<Object> accepts, Function<Object, Object> converter, HostAccess.TargetMappingPrecedence precedence);
    
    // Build the configuration
    public HostAccess build();
}

Custom HostAccess Example:

// Custom access policy
HostAccess customAccess = HostAccess.newBuilder()
    .allowPublicAccess(true)
    .allowArrayAccess(true)
    .allowListAccess(true)
    .allowMapAccess(false)        // Disable map access
    .allowIterableAccess(true)
    .methodScoping(true)          // Enable method scoping for security
    .allowAccessAnnotatedBy(HostAccess.Export.class)
    .targetTypeMapping(String.class, Integer.class, 
        s -> s.matches("\\d+"), 
        s -> Integer.parseInt((String) s))
    .build();

Context context = Context.newBuilder("js")
    .allowHostAccess(customAccess)
    .build();

// String to Integer conversion will work automatically
Value jsBindings = context.getBindings("js");
jsBindings.putMember("data", Arrays.asList("123", "456", "789"));
Value sum = context.eval("js", "data.reduce((a, b) => a + b, 0)"); // Auto-converts strings to ints
System.out.println(sum.asInt()); // 1368

HostAccess Annotations

@HostAccess.Export

Marks fields, methods, and constructors as accessible from guest languages:

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Export {
}

@HostAccess.Implementable

Marks interfaces that guest languages can implement:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Implementable {
}

@HostAccess.DisableMethodScoping

Disables method scoping for specific elements:

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DisableMethodScoping {
}

Annotation Examples:

public class SecureAPI {
    @HostAccess.Export
    public String version = "1.0.0";
    
    @HostAccess.Export
    public String getInfo() {
        return "Secure API Information";
    }
    
    @HostAccess.Export
    @HostAccess.DisableMethodScoping
    public void unscopedMethod() {
        // This method won't be scoped even if method scoping is enabled
    }
    
    // This method is not accessible from guest languages
    public String internalMethod() {
        return "Internal use only";
    }
}

@HostAccess.Implementable
public interface EventListener {
    void onEvent(String eventType, Object data);
}

// Usage
Context context = Context.newBuilder("js")
    .allowHostAccess(HostAccess.EXPLICIT)
    .build();

context.getBindings("js").putMember("api", new SecureAPI());
context.getBindings("js").putMember("EventListener", EventListener.class);

context.eval("js", """
    console.log(api.version);       // Works - exported field
    console.log(api.getInfo());     // Works - exported method
    
    // Implement Java interface in JavaScript
    let listener = new EventListener({
        onEvent: function(type, data) {
            console.log(`Event: ${type}, Data: ${data}`);
        }
    });
    """);

Target Type Mappings

Target type mappings enable automatic conversion between types:

public enum TargetMappingPrecedence {
    HIGHEST, HIGH, NORMAL, LOW, LOWEST
}

public enum MutableTargetMapping {
    ENABLED, DISABLED
}

Type Mapping Example:

HostAccess customMapping = HostAccess.newBuilder()
    .allowPublicAccess(true)
    // Convert JavaScript objects to Java Maps
    .targetTypeMapping(Value.class, Map.class,
        Value::hasMembers,
        v -> {
            Map<String, Object> map = new HashMap<>();
            for (String key : v.getMemberKeys()) {
                map.put(key, v.getMember(key).as(Object.class));
            }
            return map;
        })
    // Convert Java LocalDate to JavaScript Date-like object
    .targetTypeMapping(LocalDate.class, Value.class,
        Objects::nonNull,
        date -> ProxyObject.fromMap(Map.of(
            "year", date.getYear(),
            "month", date.getMonthValue(),
            "day", date.getDayOfMonth()
        )))
    .build();

Context context = Context.newBuilder("js")
    .allowHostAccess(customMapping)
    .build();

Polyglot Access Control

PolyglotAccess controls cross-language evaluation and bindings access between different guest languages.

Predefined PolyglotAccess Policies

public final class PolyglotAccess {
    // Full cross-language access
    public static final PolyglotAccess ALL;
    
    // No cross-language access
    public static final PolyglotAccess NONE;
}

Custom PolyglotAccess Configuration

// Factory method
public static PolyglotAccess.Builder newBuilder();

The PolyglotAccess.Builder provides granular control over language interactions:

public static final class PolyglotAccess.Builder {
    // Allow evaluation from one language to another
    public PolyglotAccess.Builder allowEval(String from, String to);
    
    // Allow mutual evaluation between languages
    public PolyglotAccess.Builder allowEvalBetween(String... languages);
    
    // Allow access to polyglot bindings
    public PolyglotAccess.Builder allowBindingsAccess(String language);
    
    // Deny evaluation (override previous allows)
    public PolyglotAccess.Builder denyEval(String from, String to);
    public PolyglotAccess.Builder denyEvalBetween(String... languages);
    public PolyglotAccess.Builder denyBindingsAccess(String language);
    
    // Build the configuration
    public PolyglotAccess build();
}

PolyglotAccess Examples:

// Allow JavaScript to evaluate Python, but not vice versa
PolyglotAccess restrictedPolyglot = PolyglotAccess.newBuilder()
    .allowEval("js", "python")
    .allowBindingsAccess("js")
    .build();

Context context = Context.newBuilder("js", "python")
    .allowPolyglotAccess(restrictedPolyglot)
    .build();

// This works - JavaScript can evaluate Python
context.eval("js", """
    let pythonResult = Polyglot.eval('python', '2 + 2');
    console.log(pythonResult);  // 4
    """);

// This would fail - Python cannot evaluate JavaScript
// context.eval("python", "polyglot.eval(language='js', string='1 + 1')");

// Selective language interaction
PolyglotAccess selectiveAccess = PolyglotAccess.newBuilder()
    .allowEvalBetween("js", "python")       // Mutual JS <-> Python
    .allowEval("ruby", "js")                // Ruby -> JS only
    .allowBindingsAccess("js")              // Only JS can access bindings
    .denyEval("python", "ruby")             // Explicitly deny Python -> Ruby
    .build();

Sandbox Policies

SandboxPolicy defines different levels of security isolation for polyglot contexts.

Sandbox Policy Levels

public enum SandboxPolicy {
    /**
     * No restrictions - full trust (default)
     */
    TRUSTED,
    
    /**
     * Basic restrictions for potentially unsafe operations
     */
    CONSTRAINED,
    
    /**
     * Enhanced isolation with method scoping enabled
     */
    ISOLATED,
    
    /**
     * Maximum restrictions for untrusted code execution
     */
    UNTRUSTED;
    
    // Comparison methods
    public boolean isStricterThan(SandboxPolicy other);
    public boolean isStricterOrEqual(SandboxPolicy other);
}

Sandbox Policy Examples:

// Trusted environment (default) - no restrictions
Context trustedContext = Context.newBuilder("js")
    .sandbox(SandboxPolicy.TRUSTED)
    .allowAllAccess(true)
    .build();

// Constrained environment - basic restrictions
Context constrainedContext = Context.newBuilder("js")
    .sandbox(SandboxPolicy.CONSTRAINED)
    .allowHostAccess(HostAccess.CONSTRAINED)
    .allowIO(IOAccess.NONE)
    .build();

// Isolated environment - enhanced security
Context isolatedContext = Context.newBuilder("js")
    .sandbox(SandboxPolicy.ISOLATED)
    .allowHostAccess(HostAccess.ISOLATED)
    .allowPolyglotAccess(PolyglotAccess.NONE)
    .allowCreateThread(false)
    .build();

// Untrusted environment - maximum restrictions
Context untrustedContext = Context.newBuilder("js")
    .sandbox(SandboxPolicy.UNTRUSTED)
    .allowHostAccess(HostAccess.UNTRUSTED)
    .allowPolyglotAccess(PolyglotAccess.NONE)
    .allowIO(IOAccess.NONE)
    .allowCreateThread(false)
    .allowCreateProcess(false)
    .allowNativeAccess(false)
    .build();

// Check sandbox policy strictness
SandboxPolicy current = SandboxPolicy.CONSTRAINED;
System.out.println(current.isStricterThan(SandboxPolicy.TRUSTED));    // true
System.out.println(current.isStricterThan(SandboxPolicy.UNTRUSTED));  // false

Environment Access Control

EnvironmentAccess controls access to environment variables and system properties.

Predefined EnvironmentAccess Policies

public final class EnvironmentAccess {
    // Inherit environment variables from the host process
    public static final EnvironmentAccess INHERIT;
    
    // No access to environment variables
    public static final EnvironmentAccess NONE;
}

Custom EnvironmentAccess Configuration

// Factory method
public static EnvironmentAccess.Builder newBuilder();

EnvironmentAccess Examples:

// Inherit host environment
Context inheritContext = Context.newBuilder("js")
    .allowEnvironmentAccess(EnvironmentAccess.INHERIT)
    .build();

// No environment access
Context restrictedContext = Context.newBuilder("js")
    .allowEnvironmentAccess(EnvironmentAccess.NONE)
    .build();

// Custom environment configuration
EnvironmentAccess customEnv = EnvironmentAccess.newBuilder()
    .allowEnvironmentAccess(Map.of(
        "APP_NAME", "MyApplication",
        "APP_VERSION", "1.0.0"
    ))
    .build();

Context customContext = Context.newBuilder("js")
    .allowEnvironmentAccess(customEnv)
    .build();

Complete Security Configuration Example

Here's a comprehensive example showing how to configure a secure polyglot context:

public class SecurePolyglotSetup {
    
    public static Context createSecureContext() {
        // Custom host access with specific permissions
        HostAccess secureHostAccess = HostAccess.newBuilder()
            .allowPublicAccess(false)                    // Disable public access
            .allowAccessAnnotatedBy(HostAccess.Export.class) // Only @Export members
            .allowArrayAccess(true)                      // Allow array operations
            .allowListAccess(true)                       // Allow list operations
            .allowMapAccess(false)                       // Disable map access
            .methodScoping(true)                         // Enable method scoping
            .allowAccessInheritance(false)               // Disable inheritance access
            .build();
        
        // Restricted polyglot access
        PolyglotAccess polyglotAccess = PolyglotAccess.newBuilder()
            .allowEval("js", "python")                   // JS can call Python
            .allowBindingsAccess("js")                   // Only JS can use bindings
            .build();
        
        // Custom environment with minimal exposure
        EnvironmentAccess envAccess = EnvironmentAccess.newBuilder()
            .allowEnvironmentAccess(Map.of(
                "NODE_ENV", "production",
                "LOG_LEVEL", "info"
            ))
            .build();
        
        // Resource limits
        ResourceLimits limits = ResourceLimits.newBuilder()
            .statementLimit(100000, null)               // Limit statement execution
            .onLimit(event -> {
                System.err.println("Resource limit exceeded: " + event.getLimitType());
            })
            .build();
        
        // Build secure context
        return Context.newBuilder("js", "python")
            .sandbox(SandboxPolicy.CONSTRAINED)         // Apply sandboxing
            .allowHostAccess(secureHostAccess)          // Restricted host access
            .allowPolyglotAccess(polyglotAccess)        // Limited polyglot access
            .allowEnvironmentAccess(envAccess)          // Custom environment
            .allowIO(IOAccess.NONE)                     // No I/O access
            .allowCreateThread(false)                   // No thread creation
            .allowCreateProcess(false)                  // No process creation
            .allowNativeAccess(false)                   // No native access
            .resourceLimits(limits)                     // Apply resource limits
            .build();
    }
    
    public static void main(String[] args) {
        try (Context context = createSecureContext()) {
            // Set up secure API
            SecureAPI api = new SecureAPI();
            context.getBindings("js").putMember("secureAPI", api);
            
            // Execute user code safely
            Value result = context.eval("js", """
                let data = [1, 2, 3, 4, 5];
                let sum = data.reduce((a, b) => a + b, 0);
                secureAPI.processResult(sum);
                """);
            
            System.out.println("Execution completed safely: " + result);
            
        } catch (PolyglotException e) {
            if (e.isResourceExhausted()) {
                System.err.println("Resource limits exceeded");
            } else if (e.isHostException()) {
                System.err.println("Host access violation: " + e.getMessage());
            } else {
                System.err.println("Execution error: " + e.getMessage());
            }
        }
    }
}

class SecureAPI {
    @HostAccess.Export
    public String processResult(int value) {
        if (value < 0 || value > 1000000) {
            throw new IllegalArgumentException("Value out of allowed range");
        }
        return "Processed: " + value;
    }
    
    // This method is not accessible due to lack of @Export
    public void dangerousOperation() {
        System.exit(1); // This cannot be called from guest code
    }
}

Security Best Practices

1. Principle of Least Privilege

// Start with most restrictive policy and add permissions as needed
Context context = Context.newBuilder("js")
    .sandbox(SandboxPolicy.UNTRUSTED)           // Most restrictive
    .allowHostAccess(HostAccess.NONE)           // No host access initially
    .allowPolyglotAccess(PolyglotAccess.NONE)   // No cross-language access
    .allowIO(IOAccess.NONE)                     // No I/O access
    .build();

2. Input Validation and Sanitization

public class ValidatedAPI {
    @HostAccess.Export
    public String processUserInput(String input) {
        if (input == null || input.length() > 1000) {
            throw new IllegalArgumentException("Invalid input length");
        }
        
        // Sanitize input
        String sanitized = input.replaceAll("[<>\"'&]", "");
        
        return "Processed: " + sanitized;
    }
}

3. Resource Monitoring

ResourceLimits limits = ResourceLimits.newBuilder()
    .statementLimit(50000, source -> !source.isInternal())
    .onLimit(event -> {
        // Log security event
        SecurityLogger.logResourceExhaustion(
            event.getLimitType(), 
            event.getConsumed(), 
            event.getLimit()
        );
        
        // Take action (e.g., terminate context)
        throw new SecurityException("Resource limit exceeded: " + event.getLimitType());
    })
    .build();

4. Execution Timeouts

Context context = Context.create("js");
CompletableFuture<Value> future = CompletableFuture.supplyAsync(() -> {
    return context.eval("js", userProvidedCode);
});

try {
    Value result = future.get(5, TimeUnit.SECONDS); // 5 second timeout
} catch (TimeoutException e) {
    context.close(true); // Force close context
    throw new SecurityException("Code execution timeout");
}

5. Security Audit Logging

public class SecurityAuditLogger {
    
    public static void logHostAccess(String member, Object target) {
        // Log all host access attempts
        System.err.printf("Host access: %s on %s%n", member, target.getClass());
    }
    
    public static void logPolyglotEval(String fromLang, String toLang, String code) {
        // Log cross-language evaluations
        System.err.printf("Polyglot eval: %s -> %s: %s%n", fromLang, toLang, 
            code.length() > 50 ? code.substring(0, 50) + "..." : code);
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-graalvm-polyglot--graalvm-sdk

docs

context-management.md

index.md

io-filesystem.md

language-execution.md

monitoring-management.md

proxy-system.md

security-access.md

value-interop.md

tile.json