Yes, but it's not obvious how to sanitize input in this case, or that it even needs sanitizing. Formatting a string sounds pretty innocuous.
[0] it also supports mapping and sequence lookups IIRC but that's about the same thing
For instance, suppose we want to allow user formatting of contact information. A contact entry has a name, address, phone number, and email address. The user supplies a template string using %_NAME_, %_ADDR_, %_PHONE_, and %_EMAIL where they would like the name, address, phone number, and email address substituted, respectively.
I'd probably be doing this in Perl, and I'd do it something like this:
sub format_contact
{
my($template, $name, $addr, $phone, $email) = @_;
my %val = (name => $name, addr => $addr,
phone => $phone, email => $email);
$template =~ s/%_([a-z]+)_/$val{lc($1)}/gi;
return $template;
} import re
def sanitize(user_input):
"""Sanitize user input for str.format
Usage:
sanitize("{post.title} - {post.blog.title}")
sanitize("{post.title}: Another fine post by "{post.author}")
sanitize("~~~ xXx {post.blog.__init__.dbconnection.__keys__.password} xXx ~~~")
"""
return re.sub(r'{[^}]*__[^}]*}', '', user_input)
Even better, we could specify which variables to allow in user input: import re
def sanitize(user_input, *allowed_variables):
"""Sanitize user input for str.format
Usage:
allowed_variables = ["post.blog.title", "post.title", "post.author"]
sanitize("{post.title} - {post.blog.title}", *allowed_variables)
sanitize("{post.title}: Another fine post by "{post.author}", *allowed_variables)
sanitize("~~~ xXx {post.blog.__init__.dbconnection.__keys__.password} xXx ~~~", *allowed_variables)
"""
for match in re.finditer(r'{([^}]*)}', user_input):
if match[1] not in allowed_variables:
user_input = user_input.replace(match[0], '')
return user_input