From 1749e1b6427f981975f32f6664bae90b7183763d Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 5 Sep 2025 08:26:58 -0700 Subject: [PATCH] annotationlib: add note on security to docs (GH-138508) (cherry picked from commit 9158bcf86b54df419cab3131412c25edd11fb0d5) Co-authored-by: Jelle Zijlstra --- Doc/library/annotationlib.rst | 24 ++++++++++++++++++++++++ Doc/library/inspect.rst | 5 +++++ Doc/library/typing.rst | 10 ++++++++++ 3 files changed, 39 insertions(+) diff --git a/Doc/library/annotationlib.rst b/Doc/library/annotationlib.rst index b31be97d045191..d6f5055955e8cf 100644 --- a/Doc/library/annotationlib.rst +++ b/Doc/library/annotationlib.rst @@ -46,6 +46,10 @@ and :func:`call_annotate_function`, as well as the :func:`call_evaluate_function` function for working with :term:`evaluate functions `. +.. caution:: + + Most functionality in this module can execute arbitrary code; see + :ref:`the security section ` for more information. .. seealso:: @@ -604,3 +608,23 @@ Below are a few examples of the behavior with unsupported expressions: >>> def ifexp(x: 1 if y else 0): ... >>> get_annotations(ifexp, format=Format.STRING) {'x': '1'} + +.. _annotationlib-security: + +Security implications of introspecting annotations +-------------------------------------------------- + +Much of the functionality in this module involves executing code related to annotations, +which can then do arbitrary things. For example, +:func:`get_annotations` may call an arbitrary :term:`annotate function`, and +:meth:`ForwardRef.evaluate` may call :func:`eval` on an arbitrary string. Code contained +in an annotation might make arbitrary system calls, enter an infinite loop, or perform any +other operation. This is also true for any access of the :attr:`~object.__annotations__` attribute, +and for various functions in the :mod:`typing` module that work with annotations, such as +:func:`typing.get_type_hints`. + +Any security issue arising from this also applies immediately after importing +code that may contain untrusted annotations: importing code can always cause arbitrary operations +to be performed. However, it is unsafe to accept strings or other input from an untrusted source and +pass them to any of the APIs for introspecting annotations, for example by editing an +``__annotations__`` dictionary or directly creating a :class:`ForwardRef` object. diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index e8d1176f477866..1061ae8849f48f 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1289,6 +1289,11 @@ Classes and functions This is an alias for :func:`annotationlib.get_annotations`; see the documentation of that function for more information. + .. caution:: + + This function may execute arbitrary code contained in annotations. + See :ref:`annotationlib-security` for more information. + .. versionadded:: 3.10 .. versionchanged:: 3.14 diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 9dbac8ce75d489..b20e1bcc1f012a 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -3360,6 +3360,11 @@ Introspection helpers See also :func:`annotationlib.get_annotations`, a lower-level function that returns annotations more directly. + .. caution:: + + This function may execute arbitrary code contained in annotations. + See :ref:`annotationlib-security` for more information. + .. note:: If any forward references in the annotations of *obj* are not resolvable @@ -3506,6 +3511,11 @@ Introspection helpers See the documentation for :meth:`annotationlib.ForwardRef.evaluate` for the meaning of the *owner*, *globals*, *locals*, *type_params*, and *format* parameters. + .. caution:: + + This function may execute arbitrary code contained in annotations. + See :ref:`annotationlib-security` for more information. + .. versionadded:: 3.14 .. data:: NoDefault