Dart code loaded from a remote URI or reflected over via dart:mirrors
ID |
dart.code.code_injection |
Severity |
high |
Remediation Complexity |
hard |
Remediation Risk |
high |
Remediation Effort |
medium |
Resource |
Code |
Language |
Dart |
Description
Dart code is loaded from a remote URI at runtime (Isolate.spawnUri(Uri.parse('http(s)://…'))) or reflected over via dart:mirrors. Both bypass the integrity guarantees of the shipped binary and let an attacker control the executing code.
Rationale
Two distinct anti-patterns:
-
Isolate.spawnUriwith a remote URI: spawns a new Dart isolate from code fetched over the network. An attacker who can serve the URI (DNS spoofing, captive portal, server compromise) runs arbitrary Dart with the app’s full privileges. Even an HTTPS URL is dangerous if the certificate is not pinned. Bundled-asset URIs andpackage:URIs are safe because the code ships with the app and is signed with the rest of the binary. -
dart:mirrors: enables runtime metaprogramming. It is unsupported in Flutter AOT builds (flutter build apk/ipa), but apps that include it in source signal a non-standard runtime path and may be vulnerable to reflection-based bypasses of access controls (mirror.invoke(privateMethod)) that the type system would otherwise prevent. Worth flagging for audit.
Combined, these patterns let untrusted bytes become running code — the textbook definition of CWE-94 (code injection).
The following code illustrates a vulnerable pattern detected by this rule:
// Positive cases for dart.code_injection.
import 'dart:isolate';
// VULNERABLE: Dart code loaded from a remote URI or reflected over via dart:mirrors
import 'dart:mirrors';
Remediation
Bundle all Dart code at build time. Do not download executable
code at runtime; for data-driven UI changes use config files
(JSON / YAML loaded as data, not eval’d). Remove dart:mirrors
imports from Flutter apps.
// Vulnerable
await Isolate.spawnUri(Uri.parse('https://example.com/code.dart'), [], null);
import 'dart:mirrors'; // unusual in Flutter apps
// Fixed: bundled code only
await Isolate.spawn(workerEntry, port.sendPort);
// Fixed: data-driven config — load JSON, never eval
final config = jsonDecode(await rootBundle.loadString('assets/config.json'));
References
-
OWASP Top 10 2025 - A05 : Injection.
-
OWASP Top 10 2025 - A08 : Software or Data Integrity Failures.
-
CWE-829 — Inclusion of Functionality from Untrusted Control Sphere
-
Isolate.spawnUri — Dart API docs — Reference for spawn-from-URI; documents the trust assumptions
-
Talsec — OWASP Mobile Top 10 for Flutter M7 — Binary protection / integrity expectations on Flutter