Vulnerability in str.format() in Python
str.format() is one of the string formatting methods in Python, which allows multiple substitutions and value formatting. This method lets us concatenate elements within a string through positional formatting. But the vulnerability comes when our Python app uses str.format in the user-controlled string.
Let’s understand with the help of an example:
# Sensitive configuration data
CONFIG = {
"KEY": "ASXFYFGK78989"
}
class Person:
def __init__(self, s1, s2):
self.s1 = s1
self.s2 = s2
def fun(template, person):
return template.format(person_obj=person)
# Create a person object
person = Person("GEEKS", "FORGEEKS")
# Case 1: Safe input
a= "Avatar_{person_obj.s1}_{person_obj.s2}"
print(fun(a, person))
# Case 2: Malicious input
b= "{person_obj.__init__.__globals__[CONFIG][KEY]}"
print(fun(b, person))
Output
Avatar_GEEKS_FORGEEKS ASXFYFGK78989
Explanation:
Person
Class: This class defines a template for creating people withs1
ands2
attributes.fun
Function: This function dynamically formats a string using theperson
object.- Case 1 (Safe input):This is the expected, safe result, where the placeholders are replaced with valid values from the
person
object. - Case 2(Malicious Input):This is a dangerous situation where a malicious user can exploit the
str.format()
method to retrieve sensitive data from the global context.
Why is Case 2 a Vulnerability?
str.format()
method can evaluate expressions within the format string, allowing access to variables and object details. This means a user can manipulate the input to access sensitive data, like the CONFIG
dictionary. This creates a security risk because attackers could retrieve information they should not have access to.
Using f-strings
f-strings provide a more controlled way of formatting strings and do not evaluate arbitrary expressions. They are safer and faster than str.format()
.
class Person:
def __init__(self, s1, s2):
self.s1 = s1
self.s2= s2
# Create a person object
person = Person("Geeks", "ForGeeks")
# Use f-string for formatting
a = f"Avatar_{person.s1}_{person.s2}"
print(a)
Output
Avatar_Geeks_ForGeeks
Explanation:
- Class and Object : P
erson
class is defined with attributess1
ands2
, and an objectperson
is created with values"Geeks"
fors1
and"ForGeeks"
fors2
. - f-string Formatting: This is used to format and print the string as
"Avatar_Geeks_ForGeeks"
, inserting the values ofperson.s1
andperson.s2
.
Using string.Template class
This is a
simpler, safer alternative to str.format()
, as it only supports simple placeholder replacements ($variable
) and does not evaluate Python expressions.
from string import Template
class Person:
def __init__(self, s1, s2):
self.s1 = s1
self.s2= s2
# Create a person object
person = Person("Geeks", "ForGeeks")
# Safe way using string.Template
template = Template("Avatar_${s1}_${s2}")
a = template.substitute(s1=person.s1, s2=person.s2)
print(a)
Output
Avatar_Geeks_ForGeeks
Explanation:
- Class and Object:
Person
class is created withs1
ands2
attributes, and aperson
object is initialized with"Geeks"
and"ForGeeks"
. - Template Substitution:
This
substitutes${s1}
and${s2}
with the object's attributes.