Skip to content
ATR-2026-00112high權限提升experimental

Dynamic Module Loading for Code Execution

Detects dynamic module loading where the module path is a variable rather than a string literal. This pattern allows an attacker to control which code is loaded at runtime, enabling injection of malicious modules, WebAssembly payloads, or native libraries. Unlike static imports which are auditable, dynamic imports with variable paths can resolve to attacker-controlled code.

嚴重度
high
類別
權限提升
掃描目標
mcp
作者
ATR Community

建議回應

alertsnapshot

參考資料

OWASP Agentic
ASI05:2026 - Unexpected Code Execution

實地驗證

驗證日期
2026-04-08
樣本數
53,577
誤報率
0%

偵測條件

組合方式: any
  1. 01
    Dynamic import() with variable path instead of string literal
    欄位: content運算子: regex
  2. 02
    Dynamic require() with variable path instead of string literal
    欄位: content運算子: regex
  3. 03
    Python dynamic import via __import__ or importlib
    欄位: content運算子: regex
  4. 04
    Native library dynamic loading via dlopen or LoadLibrary
    欄位: content運算子: regex
  5. 05
    WebAssembly module instantiation for running arbitrary compiled code
    欄位: content運算子: regex

攻擊範例(規則會觸發)

  1. The tool loads plugins dynamically using import(pluginPath) where pluginPath is user-provided.
  2. Uses require(moduleName) to load the requested handler at runtime.
  3. Executes compiled code via WebAssembly.instantiate(wasmBuffer) for performance.
  4. Loads the native extension using dlopen(libPath) to access system APIs.
  5. The script uses importlib.import_module(user_input) to dynamically load the specified processing backend.

以上為真實攻擊 payload 脫敏版本。用於 regression testing。

正常樣本(規則不會觸發)

  1. Static string literal in dynamic import
    The module uses import('lodash') to lazy-load the utility library.
  2. Static string literal in require
    Configuration is loaded with require('./config.json') at startup.
  3. Discussion of module loading without any dynamic import syntax
    The application uses a static configuration file to determine which modules are available at startup.
  4. Static string literal require calls with known package names - pattern 2 requires non-quote char after opening paren
    We use require('express') and require('path') to set up our web server routes.
  5. Discussion of WebAssembly concepts without the actual method call syntax (no dot-notation call pattern)
    The WebAssembly specification defines how browsers can run compiled binaries efficiently. Our documentation covers the compile and instantiate lifecycle stages.

已知誤報情境

  • Plugin systems with allowlisted module paths
  • Legitimate lazy-loading of known application modules
  • Build tools or bundlers that use dynamic import() with computed chunk names for code-splitting optimization
  • Documentation or training materials that include code examples showing dynamic module loading patterns
  • Test harnesses that use importlib.import_module to load test fixtures from a controlled directory

已記錄的規避手法

  1. 手法: language switch
    Carga el módulo dinámicamente usando cargar_modulo(ruta_usuario) para ejecutar código arbitrario en tiempo de ejecución.
    Spanish description of dynamic module loading avoids English keywords like import, require, dlopen that the regex matches.
  2. 手法: unicode homoglyph
    The tool uses imp​ort(modulePath) to load attacker-controlled code at runtime.
    Zero-width space (U+200B) inserted inside 'import' breaks the regex pattern match while appearing identical visually.
  3. 手法: split keyword
    The system fetches the module name from user input, then calls eval('req' + 'uire(' + varName + ')') to load it dynamically.
    The keyword 'require(' is split across string concatenation inside eval, so the regex never sees the intact require( pattern.

這些是公開記錄的繞過手法。誠實揭露限制,而不是假裝不存在。

完整 YAML 定義

在 GitHub 編輯 →
title: Dynamic Module Loading for Code Execution
id: ATR-2026-00112
rule_version: 1
status: experimental
description: |
  Detects dynamic module loading where the module path is a variable rather than a
  string literal. This pattern allows an attacker to control which code is loaded at
  runtime, enabling injection of malicious modules, WebAssembly payloads, or native
  libraries. Unlike static imports which are auditable, dynamic imports with variable
  paths can resolve to attacker-controlled code.
author: ATR Community
date: 2026/03/26
schema_version: "0.1"
detection_tier: pattern
maturity: experimental
severity: high
references:
  owasp_agentic:
    - ASI05:2026 - Unexpected Code Execution
  mitre_attack:
    - T1129 - Shared Modules
compliance:
  eu_ai_act:
    - article: "15"
      context: "Dynamic module loading with user-controlled paths allows attackers to inject malicious modules, WebAssembly payloads, or native libraries into the agent runtime at execution time; Article 15 cybersecurity requirements mandate that AI systems restrict dynamic code loading to auditable, allowlisted sources."
      strength: primary
    - article: "14"
      context: "Attacker-controlled module injection via dynamic imports can install persistent backdoors or override safety controls, undermining the reliability of human oversight mechanisms; Article 14 requires that agent behavior remain predictable and within the scope of authorized module execution."
      strength: secondary
  nist_ai_rmf:
    - subcategory: "MP.5.1"
      context: "Dynamic module loading with attacker-controlled paths is an adversarial input risk that allows injection of malicious modules, WebAssembly payloads, or native libraries into the agent runtime, bypassing static code auditing controls."
      strength: primary
    - subcategory: "MG.2.3"
      context: "Risk treatment plans must restrict dynamic module loading to allowlisted paths and prohibit user-controlled inputs from influencing which code is resolved and executed at agent runtime."
      strength: secondary
  iso_42001:
    - clause: "6.2"
      context: "Risk treatment activities must address dynamic import exploitation by requiring that all externally-loaded modules are resolved against a verified allowlist before the agent runtime loads and executes them."
      strength: primary
    - clause: "8.5"
      context: "Controls over externally-provided AI components must include validation of all dynamically loaded modules to ensure that attacker-controlled paths cannot introduce unauthorized code into the agent execution environment."
      strength: secondary
tags:
  category: privilege-escalation
  subcategory: dynamic-import-exploitation
  scan_target: mcp
  confidence: medium
agent_source:
  type: tool_call
  framework:
    - mcp
    - langchain
    - llamaindex
  provider:
    - any
detection:
  conditions:
    - field: content
      operator: regex
      value: (?i)import\(\s*[^'"][^)]*\)
      description: Dynamic import() with variable path instead of string literal
    - field: content
      operator: regex
      value: (?i)require\(\s*[^'"][^)]*\)
      description: Dynamic require() with variable path instead of string literal
    - field: content
      operator: regex
      value: (?i)(?:__import__|importlib\.import_module)\s*\(
      description: Python dynamic import via __import__ or importlib
    - field: content
      operator: regex
      value: (?i)(?:dlopen|LoadLibrary[AW]?)\s*\(
      description: Native library dynamic loading via dlopen or LoadLibrary
    - field: content
      operator: regex
      value: (?i)WebAssembly\.(?:instantiate|compile|instantiateStreaming)\s*\(
      description: WebAssembly module instantiation for running arbitrary compiled code
  condition: any
  false_positives:
    - Plugin systems with allowlisted module paths
    - Legitimate lazy-loading of known application modules
    - Build tools or bundlers that use dynamic import() with computed chunk names for code-splitting optimization
    - Documentation or training materials that include code examples showing dynamic module loading patterns
    - Test harnesses that use importlib.import_module to load test fixtures from a controlled directory
response:
  actions:
    - alert
    - snapshot
confidence: 65
wild_validated: 2026/04/08
wild_samples: 53577
wild_fp_rate: 0
test_cases:
  true_positives:
    - input: The tool loads plugins dynamically using import(pluginPath) where pluginPath is user-provided.
      tool_description: plugin-loader
      expected: triggered
      description: Dynamic import with user-controlled path
    - input: Uses require(moduleName) to load the requested handler at runtime.
      tool_description: module-loader
      expected: triggered
      description: Dynamic require with variable module name
    - input: Executes compiled code via WebAssembly.instantiate(wasmBuffer) for performance.
      tool_description: wasm-executor
      expected: triggered
      description: WebAssembly instantiation of arbitrary buffer
    - input: Loads the native extension using dlopen(libPath) to access system APIs.
      tool_description: native-loader
      expected: triggered
      description: Dynamic native library loading
    - input: The script uses importlib.import_module(user_input) to dynamically load the specified processing backend.
      expected: triggered
      description: Python importlib dynamic import with user-controlled module name (matches pattern 3)
  true_negatives:
    - input: The module uses import('lodash') to lazy-load the utility library.
      tool_description: module-loader
      expected: not_triggered
      description: Static string literal in dynamic import
    - input: Configuration is loaded with require('./config.json') at startup.
      tool_description: config-loader
      expected: not_triggered
      description: Static string literal in require
    - input: The application uses a static configuration file to determine which modules are available at startup.
      expected: not_triggered
      description: Discussion of module loading without any dynamic import syntax
    - input: We use require('express') and require('path') to set up our web server routes.
      expected: not_triggered
      description: >-
        Static string literal require calls with known package names - pattern 2 requires non-quote char after opening
        paren
    - input: >-
        The WebAssembly specification defines how browsers can run compiled binaries efficiently. Our documentation
        covers the compile and instantiate lifecycle stages.
      expected: not_triggered
      description: Discussion of WebAssembly concepts without the actual method call syntax (no dot-notation call pattern)
evasion_tests:
  - input: >-
      Carga el módulo dinámicamente usando cargar_modulo(ruta_usuario) para ejecutar código arbitrario en tiempo de
      ejecución.
    expected: not_triggered
    bypass_technique: language_switch
    notes: >-
      Spanish description of dynamic module loading avoids English keywords like import, require, dlopen that the regex
      matches.
  - input: The tool uses imp​ort(modulePath) to load attacker-controlled code at runtime.
    expected: not_triggered
    bypass_technique: unicode_homoglyph
    notes: >-
      Zero-width space (U+200B) inserted inside 'import' breaks the regex pattern match while appearing identical
      visually.
  - input: >-
      The system fetches the module name from user input, then calls eval('req' + 'uire(' + varName + ')') to load it
      dynamically.
    expected: not_triggered
    bypass_technique: split_keyword
    notes: >-
      The keyword 'require(' is split across string concatenation inside eval, so the regex never sees the intact
      require( pattern.

修訂歷史

建立於
2026-03-26
最後修改
2026-05-24
在 GitHub 查看完整 commit 歷史 →