Import injection is a vulnerability where untrusted input influences which module or resource an application loads. In Python, this can happen through dynamic import patterns that build module names from user supplied values. The risk is not just incorrect behavior. It can become a path to arbitrary code execution or unintended local file access.
How import injection works
Import injection begins when application code lets untrusted input shape the module path, package name, or resource reference that will be loaded at runtime. The problem is often introduced by convenience patterns such as building import strings from request parameters, filenames, routing values, or plugin names.
Unlike a simple bad input bug, the danger comes from crossing a trust boundary at the loading step. If the attacker can influence what is imported, they may steer the application toward code, modules, or local resources that were never intended for that execution path.
This pattern is especially important in languages and frameworks that support dynamic loading. The vulnerability is not the import feature itself, but the failure to constrain what can be imported and from where.
Why it becomes dangerous
Import injection can turn a benign lookup into a security boundary break. If the application resolves imports from attacker-controlled names, the result may be arbitrary code execution, unintended file access, or loading of a malicious local module that shadows the intended one.
The impact depends on the surrounding runtime behavior. In some cases the attacker only changes application logic; in others the imported module executes immediately and inherits the application’s permissions, configuration, and secrets.
The highest-risk designs are those that combine dynamic imports with broad filesystem reach, loose module resolution rules, or privileged runtime contexts. Those conditions can convert a seemingly small input-handling issue into full application compromise.
Common patterns and failure points
Import injection usually appears in plugin systems, extensibility hooks, CLI tools, notebook-style environments, and code that tries to load helpers by name. A frequent mistake is treating a user-facing identifier as if it were a safe internal module reference.
Another failure point is path-based resolution. If the application accepts a partial path, relative name, or package segment and then performs import resolution automatically, the attacker may redirect the lookup to an unexpected location.
Defenders should also watch for namespace collisions. When a project imports modules from directories that can be influenced by users, deployment artifacts, or writable paths, a malicious or unintended file can win the resolution order and alter execution.
How to reduce exposure
The safest design is to avoid dynamic imports driven by untrusted input. When runtime selection is necessary, the application should map approved inputs to a fixed allowlist of module names or pre-registered handlers rather than constructing import targets directly.
Use strict validation on any value that influences loading, and keep import paths inside trusted, immutable locations. For development and deployment hygiene, review packaging, search paths, and file permissions so that untrusted content cannot shadow trusted modules.
For broader defensive guidance on insecure input handling and application loading patterns, the OWASP Top 10 remains a useful baseline reference. When imported components are selected from plugin or extension logic, secure design also benefits from the OWASP API Security Top 10, especially where request data influences backend action selection.
Risk and Threat Considerations
Import injection is risky because it lets attacker-controlled data influence code loading, which is one step away from execution. In the worst case, that means the attacker can pivot from simple input control to code execution or sensitive local file access.
Failure mechanism: The application converts untrusted input into an import target, then resolves that target with normal runtime semantics instead of a fixed allowlist. That can expose unsafe modules, unintended local resources, or maliciously placed files.
Impact: The attacker may alter program behavior, execute code in the application context, access local files, or escalate from a parsing issue into full compromise of the process.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
OWASP Non-Human Identity Top 10 and OWASP Agentic AI Top 10 define the specific risk controls and attack patterns relevant to this term.
| Framework | Control / Reference | Relevance |
|---|---|---|
| OWASP Non-Human Identity Top 10 | NHI-01 — Untrusted Input to Runtime Loading | Import injection lets input influence what code is loaded, matching NHI runtime loading abuse patterns. |
| NHI-05 — Excessive Privileges | If injected imports execute in a privileged process, the resulting impact is amplified by overprivilege. | |
| Recommendation — Constrain runtime loading paths to approved, immutable module targets and reject user-controlled import names. Run loaders with least privilege so a compromised import path cannot access broader secrets or files. | ||
| OWASP Agentic AI Top 10 | AGENT-04 — Tool and Action Authorization | The same trust-break occurs when untrusted input selects executable actions or modules at runtime. |
| Recommendation — Authorize every runtime-selected action explicitly instead of letting input choose executable behavior. | ||
Practitioner Guidance
What to watch for: Review any code path where a request value, command-line argument, configuration field, or filename is used to choose a module. If the value influences loading, it should be treated as a security-sensitive control point, not just a string manipulation detail.
Common misunderstanding: Many teams assume imports are safe because they are part of the language runtime. The real risk comes from letting attacker-controlled input decide what gets imported, especially when the selected module executes on load.
Practitioner takeaway: Prefer fixed dispatch over dynamic loading whenever you can, and treat every runtime import decision as an authorization boundary.