We are using org.camunda.feel.FeelEngine
instance to evaluate FEEL expressions and trying to find a proper way to “sandbox” this operation and give a dedicated timeout for each one, in case the user tries to execute a malicious expression.
We’ve came across the following expression as an example of such harmful snippet which can bring the instance down:
count(for x in 1..(2 ** 16) return {"power": 2 ** x}) > 0
Now, the solution we have right now is the following:
val execution = executorService.submit<Either<Failure, Any>> {
feelEngine.evalExpression(expression, variables)
}
return try {
val result = execution.get(executionTimeout, TimeUnit.MILLISECONDS)
if (result.isRight) {
Result.success((result as Right).value())
} else {
Result.failure(ScriptEngineParsingException((result as Left).value()))
}
} catch (e: Throwable) {
Result.failure(
if (e is TimeoutException) {
execution.cancel(true)
ScriptEngineExecutionTimeoutException(e)
} else {
ScriptEngineParsingException(e)
}
)
}
Basically we put the task into the thread pool’s queue and give it a predefined amount of time to finish, otherwise cancel it interruptedly. The problem with such approach is that even if the task is canceled gracefully, we notice that the thread itself is running and doing its stuff. My assumption is that the evalExpression
method doesn’t really support the cooperation mode and therefor there is no proper way of shutting it down during its execution. Do you have any advice how could we solve the issue?
Thank you in advance.