{"id":"CVE-2026-63469","aliases":["EUVD-2026-116146","GHSA-6xmv-cjr5-w3q8"],"status":"published","title":"fastapi-code-generator: Import-time RCE via response status-code key -\u003e unescaped @app.get(..., responses={...}) dict","description":"fastapi-code-generator creates FastAPI applications from OpenAPI files. Prior to 0.8.1, the generator inserts an additional response status-code key into the generated responses={...} route-decorator dictionary as a single-quoted Python string without escaping embedded quotes. A multi-response OpenAPI operation with an attacker-controlled or attacker-influenced second non-primary response key can close the dictionary-key literal and inject a valid Python expression. Syntax-breaking input only causes generation to fail, but syntactically valid generated code executes with the application's or CI process's privileges when the generated module is imported and its decorator arguments are evaluated. This additional-response-key sink is distinct from the project's separate route-path and operation-summary sinks. This issue is fixed in version 0.8.1.","severity":{"version":"4.0","score":9.3,"vector":"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","level":"critical","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00312,"percentile":0.2447,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-116","CWE-94"],"published":"2026-11-03T19:15:54Z","modified":"2026-11-09T20:00:04Z","fixes":[{"ecosystem":"PyPI","package":"fastapi-code-generator","fixed_in":["0.8.1"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"fastapi-code-generator","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.8.1"}]}]},{"source":"osv","ecosystem":"PyPI","package":"fastapi-code-generator","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.8.1"}]}],"versions":["0.0.1","0.0.10","0.0.11","0.0.12","0.0.13","0.0.14","0.0.15","0.0.16","0.0.17","0.0.18","0.0.19","0.0.2","0.0.3","0.0.4","0.0.5","0.0.6","0.0.7","0.0.8","0.0.9","0.1.0","0.1.1","0.2.0","0.2.1","0.2.2","0.2.3","0.2.4","0.2.5","0.2.6","0.2.7","0.3.0","0.3.1","0.3.2","0.3.3","0.3.4","0.3.5","0.3.6","0.4.0","0.4.1","0.4.2","0.4.3","0.4.4","0.5.0","0.5.1","0.5.2","0.5.3","0.5.3rc0","0.5.4","0.6.0","0.7.0","0.8.0"]}],"products":[{"vendor":"koxudaxi","product":"fastapi-code-generator"}],"references":[{"url":"https://github.com/koxudaxi/fastapi-code-generator/security/advisories/GHSA-6xmv-cjr5-w3q8","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://github.com/koxudaxi/fastapi-code-generator/commit/49301dbdb82170d7f50877419d994b05cb1fa2bc","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/koxudaxi/fastapi-code-generator/commit/b3b9bd66e0b0c4d8c686fda700258104615a1332","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/koxudaxi/fastapi-code-generator/releases/tag/0.8.1","tags":["x_refsource_MISC","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-63469","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-6xmv-cjr5-w3q8"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/63xxx/CVE-2026-63469.json","tags":["advisory"]},{"url":"https://github.com/koxudaxi/fastapi-code-generator","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-63469","title":"fastapi-code-generator: Import-time RCE via response status-code key -\u003e unescaped @app.get(..., responses={...}) dict","description":"fastapi-code-generator creates FastAPI applications from OpenAPI files. Prior to 0.8.1, the generator inserts an additional response status-code key into the generated responses={...} route-decorator dictionary as a single-quoted Python string without escaping embedded quotes. A multi-response OpenAPI operation with an attacker-controlled or attacker-influenced second non-primary response key can close the dictionary-key literal and inject a valid Python expression. Syntax-breaking input only causes generation to fail, but syntactically valid generated code executes with the application's or CI process's privileges when the generated module is imported and its decorator arguments are evaluated. This additional-response-key sink is distinct from the project's separate route-path and operation-summary sinks. This issue is fixed in version 0.8.1.","status":"published","published":"2026-11-03T19:15:54.707Z","modified":"2026-11-09T15:41:16.347Z","cvss":[{"version":"4.0","score":9.3,"vector":"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","level":"critical","assessor":"cna"}],"cwes":["CWE-94","CWE-116"],"updated_at":"2026-11-09T16:33:53.922525Z"}],"euvd":[{"id":"EUVD-2026-116146","description":"fastapi-code-generator creates FastAPI applications from OpenAPI files. Prior to 0.8.1, the generator inserts an additional response status-code key into the generated responses={...} route-decorator dictionary as a single-quoted Python string without escaping embedded quotes. A multi-response OpenAPI operation with an attacker-controlled or attacker-influenced second non-primary response key can close the dictionary-key literal and inject a valid Python expression. Syntax-breaking input only causes generation to fail, but syntactically valid generated code executes with the application's or CI process's privileges when the generated module is imported and its decorator arguments are evaluated. This additional-response-key sink is distinct from the project's separate route-path and operation-summary sinks. This issue is fixed in version 0.8.1.","status":"published","published":"2026-11-03T19:15:54Z","modified":"2026-11-09T15:41:16Z","cvss":[{"version":"4.0","score":9.3,"vector":"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","level":"critical"}],"updated_at":"2026-11-09T22:18:23.745512Z"}],"ghsa":[{"id":"GHSA-6xmv-cjr5-w3q8","title":"fastapi-code-generator: Import-time RCE via response status-code key -\u003e unescaped @app.get(..., responses={...}) dict","description":"### Summary\n\nfastapi-code-generator (koxudaxi) emits an operation's extra responses into the route decorator's responses={...} dict, using each response's status-code key as a single-quoted string literal without escaping the '. A ' in a status-code key closes the dict-key string and, via concatenation, injects a live expression that the decorator argument evaluates when main.py is imported (the ASGI server imports it at startup) -- code execution, no request. The status-code key is a pure data field. Verified on\nfastapi-code-generator 0.8.0 / Python 3 / FastAPI.\n\n### Details\n\n```python\n@app.get(\n '/u', response_model=None,\n responses={\n '404' + (__import__(\"os\").system('…') or \"\") + 'x': {'model': Thing}\n },\n)\ndef get_thing() -\u003e None:\n pass\n```\n\nThe responses={...} dict is emitted only when the operation has a second (non-primary) response, so the malicious key is any additional response status. The generator post-processes with black/isort, so a syntax-breaking payload aborts generation (DoS); a valid-Python concat ('+expr+', kept valid with (... or \"\")) is written and runs at import. The response content-type key is NOT a sink (normalized to 'model'). info.* are repr-escaped; operationId -\u003e function_name fails closed (DoS-resistant).\n\nNot a duplicate: same product as the path -\u003e @app.get('…') and summary -\u003e handler-docstring findings, but a different field (response status-code key) and position (the responses={...} decorator dict key). Distinct from OpenAPI Generator's python-fastapi. Models come from datamodel-code-generator (repr-escaped).\n\n### PoC\n\n`reproduce.sh` (+ `make_spec.py`) attached: generates the app and merely imports main.py; the injected expression runs at decorator evaluation and writes a marker. Verified on 0.8.0.\n\n### Impact\n\nCode execution at import/startup in any application/CI that generates a FastAPI app with\nfastapi-code-generator from an attacker-controlled or attacker-influenced spec (multi-response operation)\nand imports/serves it. Estimated Critical, e.g. `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`.\n\n### Suggested fix\n\nEscape each response status-code key for the Python string literal (escape ', \\, newlines via repr) before emitting the responses={...} dict, and validate that status-code keys are numeric / a known pattern. [maintainer-report.txt](https://github.com/user-attachments/files/29534524/maintainer-report.txt) [make_spec.py](https://github.com/user-attachments/files/29534526/make_spec.py) [reproduce.sh](https://github.com/user-attachments/files/29534527/reproduce.sh)","status":"published","published":"2026-11-09T19:46:27Z","modified":"2026-11-09T19:46:28Z","cvss":[{"version":"4.0","score":9.3,"vector":"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","level":"critical"}],"cwes":["CWE-94","CWE-116"],"updated_at":"2026-11-09T19:49:32.474537Z"}],"nvd":[{"id":"CVE-2026-63469","description":"fastapi-code-generator creates FastAPI applications from OpenAPI files. Prior to 0.8.1, the generator inserts an additional response status-code key into the generated responses={...} route-decorator dictionary as a single-quoted Python string without escaping embedded quotes. A multi-response OpenAPI operation with an attacker-controlled or attacker-influenced second non-primary response key can close the dictionary-key literal and inject a valid Python expression. Syntax-breaking input only causes generation to fail, but syntactically valid generated code executes with the application's or CI process's privileges when the generated module is imported and its decorator arguments are evaluated. This additional-response-key sink is distinct from the project's separate route-path and operation-summary sinks. This issue is fixed in version 0.8.1.","status":"published","published":"2026-11-03T20:18:15.42Z","modified":"2026-11-09T16:17:34.21Z","cvss":[{"version":"4.0","score":9.3,"vector":"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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"critical","assessor":"secondary"}],"cwes":["CWE-94","CWE-116"],"updated_at":"2026-11-09T18:15:13.699929Z"}],"osv":[{"id":"CVE-2026-63469","title":"fastapi-code-generator: Import-time RCE via response status-code key -\u003e unescaped @app.get(..., responses={...}) dict","description":"fastapi-code-generator creates FastAPI applications from OpenAPI files. Prior to 0.8.1, the generator inserts an additional response status-code key into the generated responses={...} route-decorator dictionary as a single-quoted Python string without escaping embedded quotes. A multi-response OpenAPI operation with an attacker-controlled or attacker-influenced second non-primary response key can close the dictionary-key literal and inject a valid Python expression. Syntax-breaking input only causes generation to fail, but syntactically valid generated code executes with the application's or CI process's privileges when the generated module is imported and its decorator arguments are evaluated. This additional-response-key sink is distinct from the project's separate route-path and operation-summary sinks. This issue is fixed in version 0.8.1.","status":"published","published":"2026-11-03T19:15:54.707Z","modified":"2026-11-11T02:30:42.675599023Z","cvss":[{"version":"4.0","score":9.3,"vector":"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","level":"critical"}],"cwes":["CWE-116","CWE-94"],"updated_at":"2026-11-11T11:06:49.938412Z"},{"id":"GHSA-6xmv-cjr5-w3q8","title":"fastapi-code-generator: Import-time RCE via response status-code key -\u003e unescaped @app.get(..., responses={...}) dict","description":"### Summary\n\nfastapi-code-generator (koxudaxi) emits an operation's extra responses into the route decorator's responses={...} dict, using each response's status-code key as a single-quoted string literal without escaping the '. A ' in a status-code key closes the dict-key string and, via concatenation, injects a live expression that the decorator argument evaluates when main.py is imported (the ASGI server imports it at startup) -- code execution, no request. The status-code key is a pure data field. Verified on\nfastapi-code-generator 0.8.0 / Python 3 / FastAPI.\n\n### Details\n\n```python\n@app.get(\n '/u', response_model=None,\n responses={\n '404' + (__import__(\"os\").system('…') or \"\") + 'x': {'model': Thing}\n },\n)\ndef get_thing() -\u003e None:\n pass\n```\n\nThe responses={...} dict is emitted only when the operation has a second (non-primary) response, so the malicious key is any additional response status. The generator post-processes with black/isort, so a syntax-breaking payload aborts generation (DoS); a valid-Python concat ('+expr+', kept valid with (... or \"\")) is written and runs at import. The response content-type key is NOT a sink (normalized to 'model'). info.* are repr-escaped; operationId -\u003e function_name fails closed (DoS-resistant).\n\nNot a duplicate: same product as the path -\u003e @app.get('…') and summary -\u003e handler-docstring findings, but a different field (response status-code key) and position (the responses={...} decorator dict key). Distinct from OpenAPI Generator's python-fastapi. Models come from datamodel-code-generator (repr-escaped).\n\n### PoC\n\n`reproduce.sh` (+ `make_spec.py`) attached: generates the app and merely imports main.py; the injected expression runs at decorator evaluation and writes a marker. Verified on 0.8.0.\n\n### Impact\n\nCode execution at import/startup in any application/CI that generates a FastAPI app with\nfastapi-code-generator from an attacker-controlled or attacker-influenced spec (multi-response operation)\nand imports/serves it. Estimated Critical, e.g. `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`.\n\n### Suggested fix\n\nEscape each response status-code key for the Python string literal (escape ', \\, newlines via repr) before emitting the responses={...} dict, and validate that status-code keys are numeric / a known pattern. [maintainer-report.txt](https://github.com/user-attachments/files/29534524/maintainer-report.txt) [make_spec.py](https://github.com/user-attachments/files/29534526/make_spec.py) [reproduce.sh](https://github.com/user-attachments/files/29534527/reproduce.sh)","status":"published","published":"2026-11-09T19:46:27Z","modified":"2026-11-09T20:00:04.179557445Z","cvss":[{"version":"4.0","score":9.3,"vector":"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","level":"critical"}],"cwes":["CWE-116","CWE-94"],"updated_at":"2026-11-09T20:08:38.95245Z"}]}}
