Summary
Banks prior to version 2.4.3 allows attacker-controlled tool definitions to specify arbitrary Python import paths that are dynamically resolved and invoked.
If an LLM is induced to emit a matching tool call, this unsafe import and execution chain can result in arbitrary code execution in the Banks hosting process.
Banks prior to version 2.4.3 allows attacker-controlled tool definitions to specify arbitrary Python import paths that are dynamically resolved and invoked.
If an LLM is induced to emit a matching tool call, this unsafe import and execution chain can result in arbitrary code execution in the Banks hosting process.
Affected context
This vulnerability appears in Banks deployments that:
- Use the {% completion %} extension to render LLM prompts and tool call JSON
- Allow user or model-supplied Tool JSON objects to be embedded in template output
- Rely on importlib.import_module(...) and getattr(...) to resolve the import_path field without an allowlist
It is most relevant when LLM outputs are treated as trusted tool configurations, and when the hosting process has access to sensitive resources or elevated privileges.
This vulnerability appears in Banks deployments that:
- Use the {% completion %} extension to render LLM prompts and tool call JSON
- Allow user or model-supplied Tool JSON objects to be embedded in template output
- Rely on importlib.import_module(...) and getattr(...) to resolve the import_path field without an allowlist
It is most relevant when LLM outputs are treated as trusted tool configurations, and when the hosting process has access to sensitive resources or elevated privileges.
Exploit preconditions
- Attack surface: Banks application that processes {% completion %} blocks and executes tools defined via Tool JSON in rendered templates
- Required access: Ability to influence the rendered Tool JSON (e.g., prompt injection against the LLM, control of template inputs, or direct editing of tool configuration content)
- Trigger point: LLM emits a tool_calls entry whose function.name matches the attacker-supplied tool name; Banks then resolves import_path and invokes the resulting callable with attacker-controlled arguments
- Why exploitation is possible: The import_path field is neither validated nor restricted to a safe allowlist, so any importable Python attribute (including dangerous functions such as os.system or subprocess.getoutput) can be imported and executed as a tool handler.
- Attack surface: Banks application that processes {% completion %} blocks and executes tools defined via Tool JSON in rendered templates
- Required access: Ability to influence the rendered Tool JSON (e.g., prompt injection against the LLM, control of template inputs, or direct editing of tool configuration content)
- Trigger point: LLM emits a tool_calls entry whose function.name matches the attacker-supplied tool name; Banks then resolves import_path and invokes the resulting callable with attacker-controlled arguments
- Why exploitation is possible: The import_path field is neither validated nor restricted to a safe allowlist, so any importable Python attribute (including dangerous functions such as os.system or subprocess.getoutput) can be imported and executed as a tool handler.
Why this happens
The root cause lies in dynamically importing and invoking Python callables based on untrusted input without restriction.
Banks parses Tool JSON from template output, extracts an import_path string, and uses importlib.import_module(...) followed by getattr(...) to resolve the callable associated with a tool name.
Because this chain is applied directly to attacker-controllable data and lacks an allowlist, policy enforcement, or input validation, an attacker can select arbitrary Python functions for execution.
This behavior maps to CWE-94 (Improper Control of Generation of Code) and CWE-470 (Use of Unsafe Reflection), where application logic treats data as executable configuration and performs unsafe dynamic resolution steps.
The root cause lies in dynamically importing and invoking Python callables based on untrusted input without restriction.
Banks parses Tool JSON from template output, extracts an import_path string, and uses importlib.import_module(...) followed by getattr(...) to resolve the callable associated with a tool name.
Because this chain is applied directly to attacker-controllable data and lacks an allowlist, policy enforcement, or input validation, an attacker can select arbitrary Python functions for execution.
This behavior maps to CWE-94 (Improper Control of Generation of Code) and CWE-470 (Use of Unsafe Reflection), where application logic treats data as executable configuration and performs unsafe dynamic resolution steps.
Potential impact
- Arbitrary Python function execution within the Banks hosting process
- Command execution via os.system, subprocess, or similar APIs
- Access to sensitive files, environment variables, or credentials available to the process
- Manipulation of connected systems (databases, queues, APIs) using the process's privileges
- Denial of service by crashing the process or exhausting resources
- Arbitrary Python function execution within the Banks hosting process
- Command execution via os.system, subprocess, or similar APIs
- Access to sensitive files, environment variables, or credentials available to the process
- Manipulation of connected systems (databases, queues, APIs) using the process's privileges
- Denial of service by crashing the process or exhausting resources
General mitigation guidance
Effective mitigation focuses on constraining dynamic import behavior and separating untrusted LLM output from execution paths:
- Replace free-form import_path resolution with a strict allowlist of known-safe tool implementations, mapping tool names to vetted callables.
- Treat Tool JSON from LLM outputs as untrusted data and enforce validation, rejecting any unexpected or out-of-policy tool names or configuration fields.
- Use explicit registration APIs for tools instead of resolving arbitrary modules or attributes from strings at runtime.
- Run the Banks hosting process with least privilege and constrained OS-level permissions so that, even if a tool handler misbehaves, its impact is limited.
- Consider isolating tool execution into separate, sandboxed processes or environments, passing only serialized results back to the main application.
Effective mitigation focuses on constraining dynamic import behavior and separating untrusted LLM output from execution paths:
- Replace free-form import_path resolution with a strict allowlist of known-safe tool implementations, mapping tool names to vetted callables.
- Treat Tool JSON from LLM outputs as untrusted data and enforce validation, rejecting any unexpected or out-of-policy tool names or configuration fields.
- Use explicit registration APIs for tools instead of resolving arbitrary modules or attributes from strings at runtime.
- Run the Banks hosting process with least privilege and constrained OS-level permissions so that, even if a tool handler misbehaves, its impact is limited.
- Consider isolating tool execution into separate, sandboxed processes or environments, passing only serialized results back to the main application.
How teams detect issues like this
Organizations can detect and monitor this class of vulnerability using a mix of static and runtime techniques:
- Static analysis rules that flag use of importlib.import_module(...), getattr(...), or similar reflection APIs when their inputs can be influenced by templates, LLM outputs, or other untrusted sources.
- Code review checklists that require developers to justify any dynamic import mechanisms and demonstrate that tool resolution is constrained to a vetted registry.
- Policy-based controls in CI pipelines that disallow unsafe reflection patterns or enforce centralized tool registration rather than ad hoc importing.
- Runtime logging and monitoring of tool resolution events, including recording the originating Tool JSON and resolved import paths to spot anomalous or unexpected modules being loaded.
- Optional use of automated security review tools that understand Python reflection APIs and can trace taint from external inputs into dynamic imports.
Organizations can detect and monitor this class of vulnerability using a mix of static and runtime techniques:
- Static analysis rules that flag use of importlib.import_module(...), getattr(...), or similar reflection APIs when their inputs can be influenced by templates, LLM outputs, or other untrusted sources.
- Code review checklists that require developers to justify any dynamic import mechanisms and demonstrate that tool resolution is constrained to a vetted registry.
- Policy-based controls in CI pipelines that disallow unsafe reflection patterns or enforce centralized tool registration rather than ad hoc importing.
- Runtime logging and monitoring of tool resolution events, including recording the originating Tool JSON and resolved import paths to spot anomalous or unexpected modules being loaded.
- Optional use of automated security review tools that understand Python reflection APIs and can trace taint from external inputs into dynamic imports.
Sources
| Source | Link |
|---|---|
| github. | github.com/ |

