wg-best-practices-os-developers

CWE-134: Use of Externally-Controlled Format String

Ensure that all format string functions are passed a static string which cannot be controlled by the user [MITRE 2023]

In Python, the use of string formatting combined with the ability to access a function’s __globals__ attribute can exposing internal variables and methods unless properly guarded.

Non-Compliant Code Example

This noncompliant01.py leaks the global ENCRYPTION_KEY variable due to MESSAGE + customer creating a new message_format template that is then used as a template during print.

Test:

""" Compliant Code Example """
import sys
from string import Template

# Simulating a global include of sensitive information:
ENCRYPTION_KEY = "FL4G1"

# Simulating a include per language for international support:
MESSAGE = Template("Contract '$instance_name' created for '$customer'")


class MicroService:
    """Fancy MicroService"""
    def __init__(self, instance_name):
        self.instance_name = instance_name

    def get_instance_name(self) -> str:
        """return instance_name as string"""
        return self.instance_name


def front_end(customer) -> str:
    """Display service instance"""
    mc = MicroService("big time microservice")
    print(MESSAGE.substitute(instance_name=mc.get_instance_name(),
                             customer=customer))


#####################
# exploiting above code example
#####################
if __name__ == "__main__":
    if len(sys.argv) > 1:  # running from command line
        # you can print the global encryption key by using '{0.__init__.__globals__[ENCRYPTION_KEY]}' as
        # argument.
        front_end(sys.argv[1])
    else:
        # running in your IDE, simulating command line:
        # Printing the ENCRYPTION_KEY via the global accessible object
        front_end("{0.__init__.__globals__[ENCRYPTION_KEY]}")

noncompliant01.py:

""" Non-compliant Code Example """
import sys

# Simulating a global include of sensitive information:
ENCRYPTION_KEY = "FL4G1"

# Simulating a include per language:
MESSAGE = "Contract '{0.instance_name}' created for "


class MicroService:
    """Fancy MicroService"""
    def __init__(self, instance_name):
        self.instance_name = instance_name


def front_end(customer):
    """Display service instance"""
    message_format = MESSAGE + customer
    mc = MicroService("big time microservice")
    print(message_format.format(mc))


#####################
# exploiting above code example
#####################
if __name__ == "__main__":
    if len(sys.argv) > 1:  # running from command line
        # you can print the global encryption key by using '{0.__init__.__globals__[ENCRYPTION_KEY]}' as
        # argument.
        front_end(sys.argv[1])
    else:
        # running in your IDE, simulating command line:
        # Printing the ENCRYPTION_KEY via the global accessible object
        front_end("{0.__init__.__globals__[ENCRYPTION_KEY]}")

When front_end("{0.__init__.__globals__[ENCRYPTION_KEY]}") is called:

Compliant Solution

The compliant01.py solution uses the string template module and avoids mixing different ways of assembling the text. It is considered the safest option for string templates [Bader 2023] . It also provides a getter for instance name get_instance_name to reduce mixed access to members of MicroService.

compliant01.py:

""" Compliant Code Example """
import sys
from string import Template

# Simulating a global include of sensitive information:
ENCRYPTION_KEY = "FL4G1"

# Simulating a include per language for international support:
MESSAGE = Template("Contract '$instance_name' created for '$customer'")


class MicroService:
    """Fancy MicroService"""
    def __init__(self, instance_name):
        self.instance_name = instance_name

    def get_instance_name(self) -> str:
        """return instance_name as string"""
        return self.instance_name


def front_end(customer) -> str:
    """Display service instance"""
    mc = MicroService("big time microservice")
    print(MESSAGE.substitute(instance_name=mc.get_instance_name(),
                             customer=customer))


#####################
# exploiting above code example
#####################
if __name__ == "__main__":
    if len(sys.argv) > 1:  # running from command line
        # you can print the global encryption key by using '{0.__init__.__globals__[ENCRYPTION_KEY]}' as
        # argument.
        front_end(sys.argv[1])
    else:
        # running in your IDE, simulating command line:
        # Printing the ENCRYPTION_KEY via the global accessible object
        front_end("{0.__init__.__globals__[ENCRYPTION_KEY]}")

Automated Detection

Tool Version Checker Description
Bandit 1.7.4 on Python 3.10.4 Not Available  
Pylint 2.13.9 on Python 3.10.4 Formatting a regular string which could be a f-stringpylint(consider-using-f-string)  
flake8 flake8-4.0.1 on python 3.10.4   FS002 ‘.format’ used
pycharm-python-security-scanner 1.25.1 STR100 Calling format with insecure string
Product CVE Description CVSS Rating Comment
ConsoleMe < 1.2.2 CVE-2022-27177 v3.1:9.8 A Python format string issue leading to information disclosure and potentially remote code execution.  
Zenoss Core < 4.2.5 CVE-2014-6262 ZEN-15415 Multiple format string vulnerabilities in the python module in RRDtool allow remote attackers to execute arbitrary code or cause a denial of service using the rrdtool.graph function. v3.1:7.5 related issue to CVE-2013-2131.
RRDTool < 1.4.6 CVE-2013-2131 Format string vulnerability in the rrdtool module 1.4.7 for Python, allows context-dependent attackers to cause a denial of service (crash) via format string specifiers to the rrdtool.graph function.    
   
SEI CERT C Coding Standard FIO30-C Exclude user input from format strings
SEI CERT Perl Coding Standard IDS30-PL. Exclude user input from format strings
SEI CERT Coding Standard for Java IDS06-J. Exclude unsanitized user input from format strings
ISO/IEC TR 24772:2013 Injection [RST]
MITRE CWE Pillar CWE-664: Improper Control of a Resource Through its Lifetime (4.13) (mitre.org)
MITRE CWE Base CWE-134, Uncontrolled Format String

Bibliography

   
[Python 3.10.4 docs] Format String Syntax. Available from: https://docs.python.org/3/library/string.html#formatstrings [Accessed 5 May 2024]
[MITRE 2023] CWE - CWE-134: Use of Externally-Controlled Format String (4.13) (mitre.org) Available from: https://cwe.mitre.org/data/definitions/134.html [Accessed 5 May 2024]
[Bader 2023] Python String Formatting Best Practices – Real Python. Available from: https://realpython.com/python-string-formatting/ [Accessed 5 May 2024]