0
# Security and Access Control
1
2
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.
3
4
## Host Access Policies
5
6
HostAccess controls how guest languages can interact with host (Java) objects, providing fine-grained security policies from completely open access to strict sandboxing.
7
8
### Predefined HostAccess Policies
9
10
```java { .api }
11
public final class HostAccess {
12
// Annotation-based access - only @Export members accessible
13
public static final HostAccess EXPLICIT;
14
15
// Scoped access with automatic resource cleanup
16
public static final HostAccess SCOPED;
17
18
// Full unrestricted access to all host objects
19
public static final HostAccess ALL;
20
21
// No host access allowed
22
public static final HostAccess NONE;
23
24
// Limited access suitable for constrained environments
25
public static final HostAccess CONSTRAINED;
26
27
// Method scoping enabled for enhanced isolation
28
public static final HostAccess ISOLATED;
29
30
// Strict restrictions for untrusted code execution
31
public static final HostAccess UNTRUSTED;
32
}
33
```
34
35
**Predefined Policy Examples:**
36
37
```java
38
// EXPLICIT: Only annotated members accessible
39
Context explicitContext = Context.newBuilder("js")
40
.allowHostAccess(HostAccess.EXPLICIT)
41
.build();
42
43
public class RestrictedAPI {
44
@HostAccess.Export
45
public String publicMethod() {
46
return "This is accessible";
47
}
48
49
public String privateMethod() {
50
return "This is NOT accessible";
51
}
52
}
53
54
explicitContext.getBindings("js").putMember("api", new RestrictedAPI());
55
explicitContext.eval("js", "console.log(api.publicMethod())"); // Works
56
// explicitContext.eval("js", "api.privateMethod()"); // Would throw exception
57
58
// ALL: Full access (use with caution)
59
Context openContext = Context.newBuilder("js")
60
.allowHostAccess(HostAccess.ALL)
61
.build();
62
63
// CONSTRAINED: Limited access for sandboxed execution
64
Context constrainedContext = Context.newBuilder("js")
65
.allowHostAccess(HostAccess.CONSTRAINED)
66
.sandbox(SandboxPolicy.CONSTRAINED)
67
.build();
68
```
69
70
### Custom HostAccess Configuration
71
72
```java { .api }
73
// Factory methods for custom configuration
74
public static HostAccess.Builder newBuilder();
75
public static HostAccess.Builder newBuilder(HostAccess conf);
76
```
77
78
The HostAccess.Builder provides extensive customization options:
79
80
```java { .api }
81
public static final class HostAccess.Builder {
82
// Access control methods
83
public HostAccess.Builder allowPublicAccess(boolean enabled);
84
public HostAccess.Builder allowAllImplementations(boolean enabled);
85
public HostAccess.Builder allowAllClassImplementations(boolean enabled);
86
public HostAccess.Builder allowArrayAccess(boolean enabled);
87
public HostAccess.Builder allowListAccess(boolean enabled);
88
public HostAccess.Builder allowBufferAccess(boolean enabled);
89
public HostAccess.Builder allowIterableAccess(boolean enabled);
90
public HostAccess.Builder allowIteratorAccess(boolean enabled);
91
public HostAccess.Builder allowMapAccess(boolean enabled);
92
93
// Annotation-based access
94
public HostAccess.Builder allowAccessAnnotatedBy(Class<? extends Annotation> annotation);
95
public HostAccess.Builder allowImplementationsAnnotatedBy(Class<? extends Annotation> annotation);
96
97
// Method scoping and inheritance
98
public HostAccess.Builder methodScoping(boolean enabled);
99
public HostAccess.Builder allowAccessInheritance(boolean enabled);
100
101
// Target type mappings
102
public HostAccess.Builder targetTypeMapping(Class<?> sourceType, Class<?> targetType, Predicate<Object> accepts, Function<Object, Object> converter);
103
public HostAccess.Builder targetTypeMapping(Class<?> sourceType, Class<?> targetType, Predicate<Object> accepts, Function<Object, Object> converter, HostAccess.TargetMappingPrecedence precedence);
104
105
// Build the configuration
106
public HostAccess build();
107
}
108
```
109
110
**Custom HostAccess Example:**
111
112
```java
113
// Custom access policy
114
HostAccess customAccess = HostAccess.newBuilder()
115
.allowPublicAccess(true)
116
.allowArrayAccess(true)
117
.allowListAccess(true)
118
.allowMapAccess(false) // Disable map access
119
.allowIterableAccess(true)
120
.methodScoping(true) // Enable method scoping for security
121
.allowAccessAnnotatedBy(HostAccess.Export.class)
122
.targetTypeMapping(String.class, Integer.class,
123
s -> s.matches("\\d+"),
124
s -> Integer.parseInt((String) s))
125
.build();
126
127
Context context = Context.newBuilder("js")
128
.allowHostAccess(customAccess)
129
.build();
130
131
// String to Integer conversion will work automatically
132
Value jsBindings = context.getBindings("js");
133
jsBindings.putMember("data", Arrays.asList("123", "456", "789"));
134
Value sum = context.eval("js", "data.reduce((a, b) => a + b, 0)"); // Auto-converts strings to ints
135
System.out.println(sum.asInt()); // 1368
136
```
137
138
### HostAccess Annotations
139
140
#### @HostAccess.Export
141
142
Marks fields, methods, and constructors as accessible from guest languages:
143
144
```java { .api }
145
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
146
@Retention(RetentionPolicy.RUNTIME)
147
public @interface Export {
148
}
149
```
150
151
#### @HostAccess.Implementable
152
153
Marks interfaces that guest languages can implement:
154
155
```java { .api }
156
@Target({ElementType.TYPE})
157
@Retention(RetentionPolicy.RUNTIME)
158
public @interface Implementable {
159
}
160
```
161
162
#### @HostAccess.DisableMethodScoping
163
164
Disables method scoping for specific elements:
165
166
```java { .api }
167
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.TYPE})
168
@Retention(RetentionPolicy.RUNTIME)
169
public @interface DisableMethodScoping {
170
}
171
```
172
173
**Annotation Examples:**
174
175
```java
176
public class SecureAPI {
177
@HostAccess.Export
178
public String version = "1.0.0";
179
180
@HostAccess.Export
181
public String getInfo() {
182
return "Secure API Information";
183
}
184
185
@HostAccess.Export
186
@HostAccess.DisableMethodScoping
187
public void unscopedMethod() {
188
// This method won't be scoped even if method scoping is enabled
189
}
190
191
// This method is not accessible from guest languages
192
public String internalMethod() {
193
return "Internal use only";
194
}
195
}
196
197
@HostAccess.Implementable
198
public interface EventListener {
199
void onEvent(String eventType, Object data);
200
}
201
202
// Usage
203
Context context = Context.newBuilder("js")
204
.allowHostAccess(HostAccess.EXPLICIT)
205
.build();
206
207
context.getBindings("js").putMember("api", new SecureAPI());
208
context.getBindings("js").putMember("EventListener", EventListener.class);
209
210
context.eval("js", """
211
console.log(api.version); // Works - exported field
212
console.log(api.getInfo()); // Works - exported method
213
214
// Implement Java interface in JavaScript
215
let listener = new EventListener({
216
onEvent: function(type, data) {
217
console.log(`Event: ${type}, Data: ${data}`);
218
}
219
});
220
""");
221
```
222
223
### Target Type Mappings
224
225
Target type mappings enable automatic conversion between types:
226
227
```java { .api }
228
public enum TargetMappingPrecedence {
229
HIGHEST, HIGH, NORMAL, LOW, LOWEST
230
}
231
232
public enum MutableTargetMapping {
233
ENABLED, DISABLED
234
}
235
```
236
237
**Type Mapping Example:**
238
239
```java
240
HostAccess customMapping = HostAccess.newBuilder()
241
.allowPublicAccess(true)
242
// Convert JavaScript objects to Java Maps
243
.targetTypeMapping(Value.class, Map.class,
244
Value::hasMembers,
245
v -> {
246
Map<String, Object> map = new HashMap<>();
247
for (String key : v.getMemberKeys()) {
248
map.put(key, v.getMember(key).as(Object.class));
249
}
250
return map;
251
})
252
// Convert Java LocalDate to JavaScript Date-like object
253
.targetTypeMapping(LocalDate.class, Value.class,
254
Objects::nonNull,
255
date -> ProxyObject.fromMap(Map.of(
256
"year", date.getYear(),
257
"month", date.getMonthValue(),
258
"day", date.getDayOfMonth()
259
)))
260
.build();
261
262
Context context = Context.newBuilder("js")
263
.allowHostAccess(customMapping)
264
.build();
265
```
266
267
## Polyglot Access Control
268
269
PolyglotAccess controls cross-language evaluation and bindings access between different guest languages.
270
271
### Predefined PolyglotAccess Policies
272
273
```java { .api }
274
public final class PolyglotAccess {
275
// Full cross-language access
276
public static final PolyglotAccess ALL;
277
278
// No cross-language access
279
public static final PolyglotAccess NONE;
280
}
281
```
282
283
### Custom PolyglotAccess Configuration
284
285
```java { .api }
286
// Factory method
287
public static PolyglotAccess.Builder newBuilder();
288
```
289
290
The PolyglotAccess.Builder provides granular control over language interactions:
291
292
```java { .api }
293
public static final class PolyglotAccess.Builder {
294
// Allow evaluation from one language to another
295
public PolyglotAccess.Builder allowEval(String from, String to);
296
297
// Allow mutual evaluation between languages
298
public PolyglotAccess.Builder allowEvalBetween(String... languages);
299
300
// Allow access to polyglot bindings
301
public PolyglotAccess.Builder allowBindingsAccess(String language);
302
303
// Deny evaluation (override previous allows)
304
public PolyglotAccess.Builder denyEval(String from, String to);
305
public PolyglotAccess.Builder denyEvalBetween(String... languages);
306
public PolyglotAccess.Builder denyBindingsAccess(String language);
307
308
// Build the configuration
309
public PolyglotAccess build();
310
}
311
```
312
313
**PolyglotAccess Examples:**
314
315
```java
316
// Allow JavaScript to evaluate Python, but not vice versa
317
PolyglotAccess restrictedPolyglot = PolyglotAccess.newBuilder()
318
.allowEval("js", "python")
319
.allowBindingsAccess("js")
320
.build();
321
322
Context context = Context.newBuilder("js", "python")
323
.allowPolyglotAccess(restrictedPolyglot)
324
.build();
325
326
// This works - JavaScript can evaluate Python
327
context.eval("js", """
328
let pythonResult = Polyglot.eval('python', '2 + 2');
329
console.log(pythonResult); // 4
330
""");
331
332
// This would fail - Python cannot evaluate JavaScript
333
// context.eval("python", "polyglot.eval(language='js', string='1 + 1')");
334
335
// Selective language interaction
336
PolyglotAccess selectiveAccess = PolyglotAccess.newBuilder()
337
.allowEvalBetween("js", "python") // Mutual JS <-> Python
338
.allowEval("ruby", "js") // Ruby -> JS only
339
.allowBindingsAccess("js") // Only JS can access bindings
340
.denyEval("python", "ruby") // Explicitly deny Python -> Ruby
341
.build();
342
```
343
344
## Sandbox Policies
345
346
SandboxPolicy defines different levels of security isolation for polyglot contexts.
347
348
### Sandbox Policy Levels
349
350
```java { .api }
351
public enum SandboxPolicy {
352
/**
353
* No restrictions - full trust (default)
354
*/
355
TRUSTED,
356
357
/**
358
* Basic restrictions for potentially unsafe operations
359
*/
360
CONSTRAINED,
361
362
/**
363
* Enhanced isolation with method scoping enabled
364
*/
365
ISOLATED,
366
367
/**
368
* Maximum restrictions for untrusted code execution
369
*/
370
UNTRUSTED;
371
372
// Comparison methods
373
public boolean isStricterThan(SandboxPolicy other);
374
public boolean isStricterOrEqual(SandboxPolicy other);
375
}
376
```
377
378
**Sandbox Policy Examples:**
379
380
```java
381
// Trusted environment (default) - no restrictions
382
Context trustedContext = Context.newBuilder("js")
383
.sandbox(SandboxPolicy.TRUSTED)
384
.allowAllAccess(true)
385
.build();
386
387
// Constrained environment - basic restrictions
388
Context constrainedContext = Context.newBuilder("js")
389
.sandbox(SandboxPolicy.CONSTRAINED)
390
.allowHostAccess(HostAccess.CONSTRAINED)
391
.allowIO(IOAccess.NONE)
392
.build();
393
394
// Isolated environment - enhanced security
395
Context isolatedContext = Context.newBuilder("js")
396
.sandbox(SandboxPolicy.ISOLATED)
397
.allowHostAccess(HostAccess.ISOLATED)
398
.allowPolyglotAccess(PolyglotAccess.NONE)
399
.allowCreateThread(false)
400
.build();
401
402
// Untrusted environment - maximum restrictions
403
Context untrustedContext = Context.newBuilder("js")
404
.sandbox(SandboxPolicy.UNTRUSTED)
405
.allowHostAccess(HostAccess.UNTRUSTED)
406
.allowPolyglotAccess(PolyglotAccess.NONE)
407
.allowIO(IOAccess.NONE)
408
.allowCreateThread(false)
409
.allowCreateProcess(false)
410
.allowNativeAccess(false)
411
.build();
412
413
// Check sandbox policy strictness
414
SandboxPolicy current = SandboxPolicy.CONSTRAINED;
415
System.out.println(current.isStricterThan(SandboxPolicy.TRUSTED)); // true
416
System.out.println(current.isStricterThan(SandboxPolicy.UNTRUSTED)); // false
417
```
418
419
## Environment Access Control
420
421
EnvironmentAccess controls access to environment variables and system properties.
422
423
### Predefined EnvironmentAccess Policies
424
425
```java { .api }
426
public final class EnvironmentAccess {
427
// Inherit environment variables from the host process
428
public static final EnvironmentAccess INHERIT;
429
430
// No access to environment variables
431
public static final EnvironmentAccess NONE;
432
}
433
```
434
435
### Custom EnvironmentAccess Configuration
436
437
```java { .api }
438
// Factory method
439
public static EnvironmentAccess.Builder newBuilder();
440
```
441
442
**EnvironmentAccess Examples:**
443
444
```java
445
// Inherit host environment
446
Context inheritContext = Context.newBuilder("js")
447
.allowEnvironmentAccess(EnvironmentAccess.INHERIT)
448
.build();
449
450
// No environment access
451
Context restrictedContext = Context.newBuilder("js")
452
.allowEnvironmentAccess(EnvironmentAccess.NONE)
453
.build();
454
455
// Custom environment configuration
456
EnvironmentAccess customEnv = EnvironmentAccess.newBuilder()
457
.allowEnvironmentAccess(Map.of(
458
"APP_NAME", "MyApplication",
459
"APP_VERSION", "1.0.0"
460
))
461
.build();
462
463
Context customContext = Context.newBuilder("js")
464
.allowEnvironmentAccess(customEnv)
465
.build();
466
```
467
468
## Complete Security Configuration Example
469
470
Here's a comprehensive example showing how to configure a secure polyglot context:
471
472
```java
473
public class SecurePolyglotSetup {
474
475
public static Context createSecureContext() {
476
// Custom host access with specific permissions
477
HostAccess secureHostAccess = HostAccess.newBuilder()
478
.allowPublicAccess(false) // Disable public access
479
.allowAccessAnnotatedBy(HostAccess.Export.class) // Only @Export members
480
.allowArrayAccess(true) // Allow array operations
481
.allowListAccess(true) // Allow list operations
482
.allowMapAccess(false) // Disable map access
483
.methodScoping(true) // Enable method scoping
484
.allowAccessInheritance(false) // Disable inheritance access
485
.build();
486
487
// Restricted polyglot access
488
PolyglotAccess polyglotAccess = PolyglotAccess.newBuilder()
489
.allowEval("js", "python") // JS can call Python
490
.allowBindingsAccess("js") // Only JS can use bindings
491
.build();
492
493
// Custom environment with minimal exposure
494
EnvironmentAccess envAccess = EnvironmentAccess.newBuilder()
495
.allowEnvironmentAccess(Map.of(
496
"NODE_ENV", "production",
497
"LOG_LEVEL", "info"
498
))
499
.build();
500
501
// Resource limits
502
ResourceLimits limits = ResourceLimits.newBuilder()
503
.statementLimit(100000, null) // Limit statement execution
504
.onLimit(event -> {
505
System.err.println("Resource limit exceeded: " + event.getLimitType());
506
})
507
.build();
508
509
// Build secure context
510
return Context.newBuilder("js", "python")
511
.sandbox(SandboxPolicy.CONSTRAINED) // Apply sandboxing
512
.allowHostAccess(secureHostAccess) // Restricted host access
513
.allowPolyglotAccess(polyglotAccess) // Limited polyglot access
514
.allowEnvironmentAccess(envAccess) // Custom environment
515
.allowIO(IOAccess.NONE) // No I/O access
516
.allowCreateThread(false) // No thread creation
517
.allowCreateProcess(false) // No process creation
518
.allowNativeAccess(false) // No native access
519
.resourceLimits(limits) // Apply resource limits
520
.build();
521
}
522
523
public static void main(String[] args) {
524
try (Context context = createSecureContext()) {
525
// Set up secure API
526
SecureAPI api = new SecureAPI();
527
context.getBindings("js").putMember("secureAPI", api);
528
529
// Execute user code safely
530
Value result = context.eval("js", """
531
let data = [1, 2, 3, 4, 5];
532
let sum = data.reduce((a, b) => a + b, 0);
533
secureAPI.processResult(sum);
534
""");
535
536
System.out.println("Execution completed safely: " + result);
537
538
} catch (PolyglotException e) {
539
if (e.isResourceExhausted()) {
540
System.err.println("Resource limits exceeded");
541
} else if (e.isHostException()) {
542
System.err.println("Host access violation: " + e.getMessage());
543
} else {
544
System.err.println("Execution error: " + e.getMessage());
545
}
546
}
547
}
548
}
549
550
class SecureAPI {
551
@HostAccess.Export
552
public String processResult(int value) {
553
if (value < 0 || value > 1000000) {
554
throw new IllegalArgumentException("Value out of allowed range");
555
}
556
return "Processed: " + value;
557
}
558
559
// This method is not accessible due to lack of @Export
560
public void dangerousOperation() {
561
System.exit(1); // This cannot be called from guest code
562
}
563
}
564
```
565
566
## Security Best Practices
567
568
### 1. Principle of Least Privilege
569
570
```java
571
// Start with most restrictive policy and add permissions as needed
572
Context context = Context.newBuilder("js")
573
.sandbox(SandboxPolicy.UNTRUSTED) // Most restrictive
574
.allowHostAccess(HostAccess.NONE) // No host access initially
575
.allowPolyglotAccess(PolyglotAccess.NONE) // No cross-language access
576
.allowIO(IOAccess.NONE) // No I/O access
577
.build();
578
```
579
580
### 2. Input Validation and Sanitization
581
582
```java
583
public class ValidatedAPI {
584
@HostAccess.Export
585
public String processUserInput(String input) {
586
if (input == null || input.length() > 1000) {
587
throw new IllegalArgumentException("Invalid input length");
588
}
589
590
// Sanitize input
591
String sanitized = input.replaceAll("[<>\"'&]", "");
592
593
return "Processed: " + sanitized;
594
}
595
}
596
```
597
598
### 3. Resource Monitoring
599
600
```java
601
ResourceLimits limits = ResourceLimits.newBuilder()
602
.statementLimit(50000, source -> !source.isInternal())
603
.onLimit(event -> {
604
// Log security event
605
SecurityLogger.logResourceExhaustion(
606
event.getLimitType(),
607
event.getConsumed(),
608
event.getLimit()
609
);
610
611
// Take action (e.g., terminate context)
612
throw new SecurityException("Resource limit exceeded: " + event.getLimitType());
613
})
614
.build();
615
```
616
617
### 4. Execution Timeouts
618
619
```java
620
Context context = Context.create("js");
621
CompletableFuture<Value> future = CompletableFuture.supplyAsync(() -> {
622
return context.eval("js", userProvidedCode);
623
});
624
625
try {
626
Value result = future.get(5, TimeUnit.SECONDS); // 5 second timeout
627
} catch (TimeoutException e) {
628
context.close(true); // Force close context
629
throw new SecurityException("Code execution timeout");
630
}
631
```
632
633
### 5. Security Audit Logging
634
635
```java
636
public class SecurityAuditLogger {
637
638
public static void logHostAccess(String member, Object target) {
639
// Log all host access attempts
640
System.err.printf("Host access: %s on %s%n", member, target.getClass());
641
}
642
643
public static void logPolyglotEval(String fromLang, String toLang, String code) {
644
// Log cross-language evaluations
645
System.err.printf("Polyglot eval: %s -> %s: %s%n", fromLang, toLang,
646
code.length() > 50 ? code.substring(0, 50) + "..." : code);
647
}
648
}
649
```