Literal Types ([PEP 586](https://www.python.org/dev/peps/pep-0586/)) allow us to type a specific literal string like `x: Literal[“foo”] = “foo”`. This is useful when we know exactly which string or set of strings we want to accept. However, I’ve run into use cases where we'd want to accept *any* literal string such as “foo”, “bar”, etc. For example, we might have a custom format string function. For security reasons, we would want the typechecker to enforce that the format string is a literal, not an arbitrary string. Otherwise, an attacker could read or write arbitrary data by changing the format string (the so-called “format string attack” [1]): ``` def my_format_string(s: str, *args: FormatArgument) -> str: … my_format_string(“hello: %A”, a) # OK my_format_string(user_controlled_string, a) # BAD ``` Likewise, if we have a custom shell execution command like `my_execute`, we might want to enforce that the command name is a literal, not an arbitrary string. Otherwise, an attacker might be able to insert arbitrary shell code in the string and execute it: ``` def my_execute(command: str, *args: str) -> None: ... my_execute("ls", file1, file2) # OK command = input() my_execute(command, file1, file2) # BAD ``` There is no way to specify the above in the current type system. # Proposal We can allow `Literal[str]`, which would represent *any* literal string: ``` from typing import Literal def my_format_string(s: Literal[str], *args: FormatArgument) -> str: … my_format_string(“hello: %A: %B”, a, b) # OK because it is a literal string. my_format_string(user_controlled_string, sensitive_data) # Type error: Expected Literal[str], got str. ``` The same goes for the shell command function: ``` def my_execute(command: Literal[str], *args: CommandArgument) -> None: … my_execute(“ls”, files) # OK my_execute(arbitrary_string, files) # Type error: Expected Literal[str], got str. ``` Other usage will work as expected: ``` from typing import Literal, TypeVar # Type variable that accepts only literal strings. TLiteral = TypeVar("TLiteral", bound=Literal[str]) def identity(s: TLiteral) -> TLiteral: ... y = identity("hello") reveal_type(y) # Literal[“hello”] s: Literal[str] y2 = identity(s) reveal_type(y2) # Literal[str] literal_string: Literal[str] s: str = literal_string # OK literal_string: Literal[str] = s # Type error literal_string: Literal[str] = “hello” # OK x = “hello” literal_string: Literal[str] = x # OK ``` ## Backward compatibility **Backward compatibility**: `Literal[str]` is acceptable at runtime, so this doesn’t require any changes to Python itself. **Reference Implementation**: This was quite easy to implement and is available in Pyre v0.9.3. **Rejected alternatives**: `T = TypeVar(“T”, bound=Literal[Any])` isn’t something allowed in PEP 586 and would anyway be too broad. It would also allow literal bools to be passed in when we want only literal strings. ## Other uses for Literal[str] Other places where it might be useful to statically enforce literal strings for safety and readability: ``` # struct struct.unpack("https://owasp.org/www-community/attacks/Format_string_attack](https://owasp.org/www-community/attacks/Format_string_attack) -- S Pradeep Kumar