-
Notifications
You must be signed in to change notification settings - Fork 5
Disable Object Macros
Most of the RiveScript implementation libraries support Object Macros by default -- usually in their own native programming language (in the case of Perl, Python and JavaScript). For example, the Python version of RiveScript has support for Python object macros on by default.
Notice: you can disable macros from being processed from RiveScript source code while still allowing the application to define macros programmatically. This way you can provide a set of 'approved' macros to offer useful functionality to the bot authors while protecting yourself from a remote code execution vulnerability.
Table of Contents:
- Default Handlers - what languages are supported by default.
- Security Implications - why this is bad.
- How to Secure It - how to disable object macros.
- Program Defined Macros - you can still define macros from your app code while blocking them from parsed RiveScript sources.
At the time of writing, these are the default object macro handlers supported when parsing RiveScript sources in various implementations:
Implementation Language | Default Object Macro Support |
---|---|
rivescript-python |
python (same version as app) |
rivescript-js | javascript |
rivescript-java | javascript |
rivescript-perl | perl |
rivescript-go | N/A* |
* Go, being a systems language, does not support any inline object macro language by default. However, it has optional support for JavaScript.
If you are loading untrusted RiveScript sources into your bot (e.g. because you're developing a bot hosting platform where you allow users to upload their own RiveScript code), you'll want to prevent the users from being able to execute arbitrary program code on your server. Consider this example:
// This is a malicious RiveScript source uploaded to a Python hosting
// site in the cloud; you wouldn't want to let users execute arbitrary
// Python code because they could do all sorts of bad things on the server!
+ do bad stuff
- OK! <call>bad_stuff</call>
> object bad_stuff python
# This example just reads off /etc/passwd but it could do anything.
with open("/etc/passwd", "r") as fh:
return fh.read()
< object
All of the implementations have a function like setHandler()
to register new language handlers (for parsing macros defined in RiveScript source code). You can set the default handler to null to disable it.
// JavaScript
let bot = new RiveScript();
bot.setHandler("javascript", null);
# Python
bot = RiveScript()
bot.set_handler("python", None)
# Perl
my $bot = new RiveScript();
$bot->setHandler("perl" => undef);
What if you still want to allow some pre-approved macros but block all user-submitted ones? Fear not! You can still programmatically define macros from your application code.
All the implementations of RiveScript have a function like setSubroutine()
that you can call from your program code to define an object macro in the same programming language as your app. Look up the documentation for exact details for your implementation.
Here is an example for JavaScript:
let bot = new RiveScript();
// Disable object macros from parsed RiveScript source codes, for security.
bot.setHandler("javascript", null);
// But we can still define our own macros safely:
bot.setSubroutine("reverse", function(rs, args) {
let message = args.join(" ");
return message.split("").reverse().join("");
});
Now, RiveScript source codes can still <call>reverse <star></call>
to use the subroutine defined above, but if the RiveScript source tries to include an > object name javascript
it will simply be ignored by the parser and not executed.