TinyRuleKit
Expression Security
Expression security is enabled by default when expressions are enabled. TinyRuleKit always applies a minimum baseline policy while security is active, then applies the configured default, custom policy, or custom validator.
This prevents a permissive project policy from accidentally allowing runtime execution, classloader access, file APIs, reflection-like access, imports, or package-qualified Java access.
This matters when rule JSON can come from external files, plugins, administration panels, or user-edited configuration. Without validation, expressions can become an injection surface for malicious code or accidental access to unsafe APIs.
Default Policy
Customize the policy when your project needs stricter rules:
import org.tinyrulekit.api.expression.security.ExpressionSecurityPolicy;
ExpressionSecurityPolicy policy = ExpressionSecurityPolicy.defaults()
.withMaxLength(200)
.withAdditionalBlockedTokens(Set.of("delete", "saveFile"));
RuleEngine<GameContext> engine = RuleEngine.builder(GameContext.class)
.conditions(GameRules::condition)
.actions(GameRules::action)
.expressionSecurityPolicy(policy)
.buildFromJson(json);
Use withBlockedTokens only when you intentionally want to
replace the project-level token set. TinyRuleKit's minimum baseline
policy still remains active unless
expressionSecurityDisabled() is called.
Public Security Tools
The public API exposes the same building blocks used by the default security layer:
import org.tinyrulekit.api.expression.security.ExpressionSecurityPolicy;
import org.tinyrulekit.api.expression.security.ExpressionValidators;
ExpressionSecurityPolicy minimumPolicy = ExpressionSecurityPolicy.minimum();
Set<String> defaultTokens = ExpressionSecurityPolicy.defaultBlockedTokens();
ExpressionValidator validator = ExpressionValidators.chain(
ExpressionValidators.fromPolicy(ExpressionSecurityPolicy.defaults()),
expression -> {
if (expression.contains("projectSecret")) {
throw new IllegalArgumentException("Expression is not allowed");
}
}
);
Most applications do not need to call
ExpressionValidators.withMinimum because the builder
already applies the minimum validator while expression security is
enabled. It is useful when the same validator is reused outside the
TinyRuleKit builder.
Project-Owned Policy
For production projects, prefer creating a named policy owned by the application instead of configuring expression security inline everywhere.
final class GameExpressionPolicies {
private GameExpressionPolicies() {
}
static ExpressionSecurityPolicy rulesFromConfigFiles() {
return ExpressionSecurityPolicy.defaults()
.withMaxLength(180)
.withAdditionalBlockedTokens(Set.of(
"Files",
"Path",
"ClassLoader",
"projectSecret"
));
}
}
Use that policy when building the engine:
RuleEngine<GameContext> engine = RuleEngine.builder(GameContext.class)
.conditions(GameRules::condition)
.actions(GameRules::action)
.expressionSecurityPolicy(GameExpressionPolicies.rulesFromConfigFiles())
.buildFromJson(json);
Custom Validator
Use expressionValidator when the security model is not a
blocked-token policy or when another expression framework has its own
validation rules:
ExpressionValidator validator = expression -> {
if (expression.contains("delete")) {
throw new IllegalArgumentException("Expression is not allowed");
}
};
RuleEngine<GameContext> engine = RuleEngine.builder(GameContext.class)
.conditions(GameRules::condition)
.actions(GameRules::action)
.expressionValidator(validator)
.buildFromJson(json);
The validator runs once per expression during engine construction, before the
configured ExpressionEngine compiles it. While expression
security is enabled, TinyRuleKit runs the minimum validator before this
custom validator.
Trust Levels
Use different named policies for different trust levels:
- bundled application resources can be less restrictive
- external configuration directories should be stricter
- administration panels should validate and review expressions
- user-authored or network-loaded rule documents should use the strictest policy
Disabling Security
Security can be disabled only for fully trusted rule sources:
RuleEngine<GameContext> engine = RuleEngine.builder(GameContext.class)
.conditions(GameRules::condition)
.actions(GameRules::action)
.expressionSecurityDisabled()
.buildFromJson(json);
Do not disable security for player-authored, user-authored, network-loaded, or plugin-loaded rule documents.
Continue with Expression Security Measures for the consumer-facing security components and the minimum-protection behavior.
Return to Expression Best Practices for design and maintenance recommendations, or Static Rule Best Practices for design and maintenance recommendations.