MarkupSafe Documentation

repository·main·Indexed 20 days ago

https://github.com/pallets/markupsafe

A library for safely adding untrusted strings to HTML/XML markup to mitigate injection attacks and XSS. It provides the Markup class and escape() function to ensure untrusted input is correctly escaped while allowing explicitly marked 'safe' content to pass through. Features include automatic escaping during string formatting and concatenation, support for the __html__ interface, and utilities like escape_silent() and soft_str().

Tokens
4.9K
Snippets
20
Records
22
Agent score
70%

What's inside MarkupSafe

  1. How Markup objects ensure safety

    main

    MarkupSafe uses a Markup class to track which strings have already been escaped. When you use escape() on a string, it returns a Markup object.

    Key behaviors:

    1. Idempotency: Calling escape() on an existing Markup object does nothing, preventing double-escaping.
    2. Safe Concatenation: When a Markup object is concatenated with a standard string, the standard string is automatically escaped before being joined. This prevents injection attacks when building HTML fragments dynamically.
    from markupsafe import escape
    
    hello = escape("<em>Hello</em>")
    # hello is now a Markup object
    
    # The string " <strong>World</strong>" is automatically escaped because it is being added to a Markup object
    combined = hello + " <strong>World</strong>"
    # combined is: Markup('&lt;em&gt;Hello&lt;/em&gt; &lt;strong&gt;World&lt;/strong&gt;')
  2. How Markup and escape interact

    main

    MarkupSafe is designed so that Markup objects are treated as 'safe'. If you pass a Markup object to escape(), it will not be escaped again, preventing double-escaping of already safe content.

    >>> from markupsafe import Markup, escape
    >>> escape(Markup("<strong>Hello</strong>"))
    Markup('<strong>hello</strong>')
  3. Use the __html__ method for custom HTML representations

    main

    MarkupSafe's escape function and Markup class support the __html__ magic method. If an object implements __html__, MarkupSafe will call this method to obtain the object's HTML representation instead of converting it to a string. The value returned by __html__ is treated as safe and will not be escaped.

    Warning: Because __html__ bypasses automatic escaping, you must manually escape any user-provided data within the string returned by your __html__ method to prevent XSS vulnerabilities.

    class Image:
        def __init__(self, url):
            self.url = url
    
        def __html__(self):
            return f'<img src="{self.url}">'
    
    img = Image("/static/logo.png")
    # Markup(img) returns Markup('<img src="/static/logo.png">')
    # escape(img) returns Markup('<img src="/static/logo.png">')
  4. Use Markup objects as format strings

    main

    The Markup class can be used as a format string. When objects are formatted into a Markup string, they are automatically escaped first to prevent XSS vulnerabilities.

    >>> Markup("Hello, {}").format("<script>")
    Markup('Hello, &lt;script&gt;')
  5. Implement the __html__ interface for custom objects

    main

    If you have a custom class that generates HTML, implement the __html__() method. When this object is passed to escape() or wrapped in Markup(), MarkupSafe will call __html__() and treat the result as safe, preventing it from being escaped again.

    from markupsafe import Markup
    
    class UserProfile:
        def __init__(self, name):
            self.name = name
    
        def __html__(self):
            return f'<span class="user">{self.name}</span>'
    
    user = UserProfile("Alice")
    # Wrapping the object in Markup calls __html__ automatically
    safe_html = Markup(user)
    print(safe_html) 
    # '<span class="user">Alice</span>'
  6. Convert an object to a string with soft_str()

    main

    Use markupsafe.soft_str() to convert an object to a string. If the object is already a Markup object, it returns it as-is; otherwise, it returns the string representation of the object. This is useful for ensuring compatibility when working with a mix of standard strings and Markup objects.

    from markupsafe import soft_str, Markup
    
    # Returns the object as-is if it is Markup
    val1 = soft_str(Markup("<b>Safe</b>"))
    
    # Converts other objects to strings
    val2 = soft_str(123)
  7. Escape text with escape()

    main

    Use the escape() function to convert untrusted text into a Markup object. This function replaces characters with special meanings (like < and >) with their safe HTML/XML entities.

    Once text is converted to a Markup object, it is marked as 'safe'. Subsequent operations (like string concatenation) with this object will automatically escape any new untrusted strings added to it, ensuring the final result remains safe for rendering.

    from markupsafe import escape
    
    # Escaping a string returns a Markup object
    hello = escape("<em>Hello</em>")
    # Output: Markup('&lt;em&gt;Hello&lt;/em&gt;')
    
    # Subsequent escapes on already escaped Markup objects are idempotent
    escape(hello)
    
    # Concatenating Markup with untrusted strings automatically escapes the new string
    result = hello + " <strong>World</strong>"
    # Output: Markup('&lt;em&gt;Hello&lt;/em&gt; &lt;strong&gt;World&lt;/strong&gt;')
  8. Escape untrusted input with escape()

    main

    Use escape() to convert a string into a Markup object where special HTML/XML characters (like < and >) are replaced with their corresponding entities. This prevents injection attacks by ensuring untrusted user input is rendered as literal text rather than executable code.

    >>> from markupsafe import escape
    >>> escape("<script>alert(document.cookie);</script>")
    Markup('&lt;script&gt;alert(document.cookie);&lt;/script&gt;')
  9. Mark text as safe using Markup

    main

    Wrap a string in Markup() to signal that the content is already safe and should not be escaped. This is useful when you have pre-formatted HTML that you want to render as-is. Note that Markup is a subclass of str, and its methods (like .format()) automatically escape arguments to maintain safety.

    >>> from markupsafe import Markup
    >>> Markup("<strong>Hello</strong>")
    Markup('<strong>hello</strong>')
    
    # Markup.format() escapes arguments automatically
    >>> template = Markup("Hello <em balance>{name}</em>")
    >>> template.format(name='"World"')
    Markup('Hello <em balance>&#34;World&#34;</em>')
  10. Escape content silently with escape_silent()

    main

    Use markupsafe.escape_silent() when you want to escape a value but do not want to raise an error if the input is not a string or is otherwise incompatible. This is useful for handling optional or unpredictable input types gracefully.

    from markupsafe import escape_silent
    
    # Returns an empty Markup object or handles non-string input without raising exceptions
    safe_val = escape_silent(None)
  11. Use printf-style formatting with Markup

    main

    You can use percent-style (%) formatting with Markup objects. Aside from the automatic escaping of the interpolated values, there is no special behavior compared to standard Python string formatting.

    >>> user_id = 3
    >>> user_name = "<script>"
    >>> Markup('<a href="/user/%d">%s</a>') % (user_id, user_name)
    Markup('<a href="/user/3">&lt;script&gt;</a>')