Nov 9, 2026·10 min read·4 visits
fastapi-code-generator versions prior to 0.8.1 fail to escape triple-double quotes when inserting OpenAPI Operation.summary strings into generated Python docstrings. Attackers controlling the input OpenAPI schema can inject arbitrary Python code that executes with the privileges of the FastAPI server process whenever the corresponding route handler is invoked.
CVE-2026-63470 (GHSA-h667-4jj2-cgv4) is a code injection vulnerability (CWE-94) in fastapi-code-generator prior to version 0.8.1. The tool generates FastAPI route handlers by directly interpolating the OpenAPI Operation.summary field into triple-double-quoted Python docstrings without escaping embedded triple quotes or backslashes. An attacker who supplies or modifies an OpenAPI specification can break out of the docstring literal and inject arbitrary Python expressions into the generated route handler body, resulting in remote code execution when the affected HTTP endpoint is called.
fastapi-code-generator is a Python command-line utility and library that parses OpenAPI (v2 and v3) specifications in YAML or JSON format and generates ready-to-run FastAPI application scaffolding. It relies on datamodel-code-generator for Pydantic model creation and uses Jinja2 templates to emit Python source files (main.py and router modules). In automated development workflows, API gateways, and CI/CD pipelines, this tool is frequently invoked to dynamically build backend service stubs from external or partner-supplied schema repositories.
Prior to version 0.8.1, fastapi-code-generator is vulnerable to Improper Control of Generation of Code (CWE-94) and Improper Encoding or Escaping of Output (CWE-116). Specifically, the parser extracts the summary attribute from each OpenAPI route operation (Operation.summary) and passes it unescaped to the Jinja2 route template. The template places this string directly inside a triple-double-quoted ("""...""") Python docstring inside the generated route-handler function.
Because the generator does not sanitize backslashes (\) or embedded triple-double quotes ("""), an attacker who controls or influences the input OpenAPI specification can prematurely terminate the docstring literal. By injecting a syntactically valid Python expression bounded by matching triple quotes, the attacker embeds executable Python statements directly into the body of the FastAPI route handler.
Unlike related injection sinks in fastapi-code-generator that execute immediately when the generated module is imported, CVE-2026-63470 operates as a call-time sink. The injected code remains dormant inside the route function definition during module startup and executes with the privileges of the FastAPI server process each time an HTTP request invokes the affected route.
The root cause of CVE-2026-63470 resides in how the Operation class in fastapi_code_generator/parser.py prepares string properties before rendering them through Jinja2 templates. During the parsing phase, fastapi-code-generator iterates over the paths and HTTP methods defined in an OpenAPI document, instantiating an Operation object for each endpoint. This object holds metadata including path, operationId, tags, additional_responses, and summary.
When generating the output Python code, the Jinja2 template constructs a FastAPI endpoint definition for each Operation instance. The template formats the Operation.summary field as the function's docstring using standard triple-double quotes:
@app.get(...)
def generated_handler(...) -> ...:
"""
{{ operation.summary }}
"""
passPrior to version 0.8.1, Jinja2 auto-escaping is either inapplicable or ineffective for Python source code generation contexts, and Operation performed no Python-literal escaping on self.summary. If an OpenAPI specification contains a summary string with unescaped """ sequences, the Python interpreter parses the first occurrence of """ as the closing delimiter of the docstring.
Any characters immediately following the injected closing delimiter are parsed as standard Python statements inside the function's local scope. If the injected payload is structured as a valid Python expression (such as string concatenation + <expression> + """), it satisfies both the Python AST parser and post-processing code formatters (black and isort) that fastapi-code-generator runs over the generated output. If the input breaks Python syntax, code generation fails during formatting; however, syntactically valid expressions persist into the final .py file.
It is important to distinguish this call-time sink from two companion import-time sinks patched in the same release (0.8.1). In unpatched versions, Operation.path (interpolated into @app.get('<path>')) and Operation.additional_responses status code keys (interpolated into the responses={'<status>': ...} dictionary within the decorator) also lacked single-quote escaping. While decorator injections execute immediately when Python imports main.py, the Operation.summary injection resides inside the function body and triggers exclusively when the FastAPI router dispatches an incoming request to that function.
The vulnerability was remediated in commits 49301dbdb82170d7f50877419d994b05cb1fa2bc and b3b9bd66e0b0c4d8c686fda700258104615a1332 by introducing explicit string-escaping wrappers in fastapi_code_generator/parser.py. Before the patch, Operation fields were stored as plain strings or unescaped UsefulStr instances and rendered directly into templates.
The patch introduces two helper functions—_escape_single_quoted_python_string and _escape_triple_double_quoted_python_string—alongside a specialized PythonEscapedString subclass of UsefulStr:
def _raw_string(value: object) -> str:
match value:
case PythonEscapedString() as escaped:
return escaped.raw
case _:
return str(value)
def _escape_single_quoted_python_string(value: object) -> str:
# Neutralizes backslashes, single quotes, and line breaks for single-quoted literals
return (
_raw_string(value)
.replace("\\", "\\\\")
.replace("'", "\\'")
.replace("\r", "\\r")
.replace("\n", "\\n")
)
def _escape_triple_double_quoted_python_string(value: object) -> str:
# Neutralizes backslashes first, then escapes triple-double-quote sequences
return _raw_string(value).replace("\\", "\\\\").replace('"""', '\\"\\"\\"')The PythonEscapedString class preserves the original unescaped value in self.raw for internal comparisons and hashing while returning the escaped string representation when converted to str during Jinja2 template rendering:
class PythonEscapedString(UsefulStr):
raw: str
def __new__(cls, raw: object, escaped: str) -> "PythonEscapedString":
value = str.__new__(cls, escaped)
value.raw = _raw_string(raw)
return value
@classmethod
def single_quoted(cls, value: object) -> "PythonEscapedString":
return cls(value, _escape_single_quoted_python_string(value))
@classmethod
def triple_double_quoted(cls, value: object) -> "PythonEscapedString":
return cls(value, _escape_triple_double_quoted_python_string(value))Within the Operation model, the patch hooks into Pydantic's model_post_init lifecycle method to sanitize all user-controlled schema fields automatically upon instantiation:
def model_post_init(self, __context: Any) -> None:
self.path = PythonEscapedString.single_quoted(self.path)
if self.summary is not None:
# Sanitize Operation.summary for triple-double-quoted docstring context
self.summary = PythonEscapedString.triple_double_quoted(self.summary)
if self.additional_responses:
self.additional_responses = {
PythonEscapedString.single_quoted(status_code): models
for status_code, models in self.additional_responses.items()
}
if self.tags:
self.tags = [PythonEscapedString.single_quoted(tag) for tag in self.tags]> [!NOTE]
> Fix Completeness Assessment: By escaping \ to \\ prior to replacing """ with \"\"\", the patch prevents bypass techniques that rely on trailing backslashes (e.g., supplying \""" to escape the first quote escape and leave "" unescaped). However, this sanitizer still permits trailing single or double " characters at the very end of self.summary. If a template placed {{ operation.summary }}""" on the same line without a trailing newline, a summary ending in " would form """" and cause a syntax error or unexpected token boundary. Because the default template places a newline before the closing """, this edge case does not allow breakout in standard usage. Additionally, if a user supplies a custom Jinja2 template via --template-dir that wraps operation.summary in triple-single quotes ('''...'''), _escape_triple_double_quoted_python_string will not neutralize ''', leaving custom single-quoted docstring templates vulnerable.
Exploiting CVE-2026-63470 requires that a target environment runs fastapi-code-generator (version < 0.8.1) against an attacker-supplied or attacker-influenced OpenAPI specification, and subsequently deploys or executes the generated FastAPI code. No authentication or special privileges are required during the code generation phase or when sending the triggering HTTP request (unless the generated application is later wrapped in external authentication middleware).
The official repository commit 49301dbdb82170d7f50877419d994b05cb1fa2bc includes a regression test fixture at tests/data/openapi/coverage/python_literal_escaping.yaml that demonstrates the exact payload structure required to exploit both the import-time sinks and the call-time summary sink:
openapi: 3.0.0
info:
title: Python literal escaping
version: 1.0.0
paths:
"/items/'+(__import__(\"os\").system(\"path\") or \"\")+'/detail":
get:
tags:
- literal escaping
summary: 'bad""" + (__import__("os").system("summary") or "") + """done'
operationId: getEscapedThing
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Thing'When an unpatched version of fastapi-code-generator processes the summary field above (fastapi-codegen --input python_literal_escaping.yaml --output .), it generates the following route handler in main.py:
@app.get(
'/items/detail',
response_model=Thing,
tags=['literal escaping'],
)
def get_escaped_thing() -> Thing:
"""
bad""" + (__import__("os").system("summary") or "") + """done
"""
passIn Python, a docstring is simply an unassigned string literal expression statement at the beginning of a function body. By injecting bad""" + (__import__("os").system("summary") or "") + """done, the attacker transforms the single string literal into a binary addition (+) expression combining three strings. Because the entire expression evaluates to a string and is not assigned to a variable, Python treats it as a valid standalone expression statement (rather than a formal __doc__ string) and compiles the function without error.
When the FastAPI server starts (e.g., via uvicorn main:app), the code inside get_escaped_thing() is not yet evaluated. As soon as an HTTP client sends a GET request to /items/detail, FastAPI invokes get_escaped_thing(), causing the Python interpreter to evaluate the string concatenation expression and execute __import__("os").system("summary") in the context of the web server process.
Successful exploitation of CVE-2026-63470 grants an attacker arbitrary Python code execution within the context of the running FastAPI application server. Because the injected expression executes inside the route handler process, the attacker inherits all operating system permissions, environment variables (such as database connection strings, API keys, and cloud IAM credentials), filesystem access, and internal network reachability assigned to the FastAPI worker process.
The vulnerability carries a CVSS v4.0 base score of 9.3 (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N). The Attack Vector is Network (AV:N) with Low Attack Complexity (AC:L) and No Attack Requirements (AT:N), reflecting that remote OpenAPI specifications are frequently ingested via URLs, webhooks, or automated Git pipelines, and routes are exposed over HTTP. Confidentiality (VC:H), Integrity (VI:H), and Availability (VA:H) impacts on the vulnerable system are all High due to unrestricted remote code execution.
From an operational standpoint, the call-time nature of this sink makes detection during CI/CD build phases more difficult than import-time sinks. Import-time injections trigger immediately during unit test collection or linter imports, potentially alerting build systems if unexpected outbound connections or process spawns occur during CI. In contrast, a payload injected via Operation.summary remains dormant during build, static formatting, and application boot, activating only when a specific HTTP endpoint is called in staging or production.
Current threat intelligence indicates an EPSS score of 0.00468 (40.75th percentile), and the vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. However, the availability of functional proof-of-concept payloads in the public commit history lowers the barrier for exploitation against automated API scaffolding services.
To remediate CVE-2026-63470, upgrade fastapi-code-generator to version 0.8.1 or later. Version 0.8.1 implements PythonEscapedString.triple_double_quoted() in fastapi_code_generator/parser.py to neutralize backslashes and embedded """ sequences in Operation.summary, as well as PythonEscapedString.single_quoted() for route paths, response status codes, and tags.
pip install --upgrade "fastapi-code-generator>=0.8.1"Upgrading the generator package alone does not fix Python source files that were previously generated using versions prior to 0.8.1. Engineering teams must regenerate all FastAPI application code (main.py and associated router modules) from their source OpenAPI specifications using the patched version. When regenerated with 0.8.1, the previously vulnerable docstring is emitted safely with escaped quotes:
def get_escaped_thing() -> Union[Thing, Error]:
"""
bad\"\"\" + (__import__("os").system("summary") or "") + \"\"\"done
"""
passFor environments where immediate regeneration is not feasible, security teams should audit existing generated FastAPI repositories for signs of docstring breakout. Specifically, inspect route handler definitions for triple-quote closures followed by concatenation operators (+), function calls, or multiple statements prior to the pass or implementation block. Additionally, verify that every route handler retains a valid __doc__ attribute at runtime (func.__doc__ is not None), as string concatenation expressions inside the docstring position prevent Python from binding the string to __doc__.
If your workflow uses the --template-dir option to supply custom Jinja2 templates to fastapi-code-generator, verify that all docstring blocks in those templates use triple-double quotes ("""...""") rather than triple-single quotes ('''...'''). Because _escape_triple_double_quoted_python_string only escapes """ and \, custom templates using ''' remain susceptible to quote breakout.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
fastapi-code-generator koxudaxi | < 0.8.1 | 0.8.1 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2026-63470 (GHSA-h667-4jj2-cgv4) |
| Primary CWE | CWE-94: Improper Control of Generation of Code ('Code Injection') |
| CVSS v4.0 Score | 9.3 CRITICAL (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N) |
| EPSS Score | 0.47% (40.75th Percentile) |
| Affected Component | fastapi-code-generator (< 0.8.1) - Operation.summary in fastapi_code_generator/parser.py |
| Trigger Mechanism | Call-time execution upon HTTP request to the generated FastAPI route handler |
| Exploit Status | PoC Available (Official test fixture in repository) |
| CISA KEV Status | Not Listed |
The software constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
CVE-2026-63475 (GHSA-96wc-2m84-2cj7) is an uncontrolled recursion and infinite loop vulnerability in isomorphic-git prior to version 1.38.6. When processing Git protocol responses from a malicious or man-in-the-middle (MitM) server, isomorphic-git writes server-advertised symbolic reference (symref) capabilities directly to the local repository filesystem without validating for circular dependencies. Because the reference resolution logic in GitRefManager.resolve() lacks both cycle detection and a default recursion depth limit, any subsequent operation that resolves the circular references enters a non-terminating asynchronous recursion loop. Because the malicious references are persisted on disk, this condition induces a persistent denial of service (DoS) against the affected repository.
CVE-2026-16454 is an object-level authorization bypass vulnerability (CWE-284, CWE-862) in Eclipse hawkBit versions 1.0.3 and prior. The flaw exists within the Direct Device Integration (DDI) REST controller (hawkbit-ddi-resource), where endpoints responsible for enumerating software module metadata and serving firmware binaries fail to verify whether the requested software module is assigned to the authenticated device. Consequently, any device with valid credentials (such as a TargetToken or GatewayToken) can enumerate software module identifiers and download arbitrary firmware artifacts across the entire tenant namespace.
CVE-2026-62284 (GHSA-5w5g-j6hw-6p8f) is a code injection and server-side request forgery vulnerability in the console-proxy component of the OSAC Operator. The RemoteConfigResolver parses Kubernetes Secrets containing kubeconfig files via clientcmd.RESTConfigFromKubeConfig without sanitizing execution-related fields. An attacker with RBAC permissions to create or modify labeled Secrets in monitored namespaces can supply a malicious exec credential plugin, resulting in arbitrary command execution within the console-proxy pod.
CVE-2026-62361 (GHSA-xgjr-7j9q-2h4r) is an authenticated SQL injection and authorization bypass vulnerability in listmonk, an open-source, self-hosted newsletter and mailing list manager written in Go. In versions prior to 6.2.0, the subscriber export endpoint (GET /api/subscribers/export) directly interpolates user-supplied SQL filter expressions into a PostgreSQL query without invoking the table allowlist validation function (validateQueryTables). Consequently, authenticated users possessing the subscribers:sql_query and subscribers:get_all permissions can bypass relational access controls, execute arbitrary subqueries against restricted tables such as users and settings, and modify database state via writable Common Table Expressions (CTEs).
CVE-2026-28385 (GHSA-3gq2-x4qg-p4g6) is a Server-Side Request Forgery (SSRF) vulnerability in Canonical LXD versions 4.12 through 6.9. An authenticated user possessing the can_create_images entitlement can force the LXD daemon to execute arbitrary outbound HTTP and HTTPS requests via the /1.0/images API endpoint. Due to the absence of egress destination validation, an attacker can probe host loopback services, RFC 1918 private network segments, and cloud Instance Metadata Services (IMDS) from the network position of the privileged LXD daemon.
Canonical LXD and LXC Incus contain an arbitrary file write vulnerability (CWE-73 / CWE-59) in the `/1.0/instances/<name>/exec` REST API endpoint. When an instance is unpacked from an image archive, top-level symbolic links are extracted directly onto the host filesystem within the instance storage directory. If a crafted image includes a symbolic link named `exec-output` pointing to an arbitrary host path, invoking the execution endpoint with `record-output: true` causes the privileged host daemon to follow the symlink and write command output files directly to the target host directory. An authenticated attacker with permissions to import images and execute commands can exploit this flaw to write controlled content to sensitive host directories such as `/etc/cron.d`, resulting in arbitrary code execution on the host as `root`.