Security

    Android dynamic code loading (DexClassLoader) security

    A 2026 view of an Android app loading a dex file at runtime with DexClassLoader, with an attacker substituting code over an insecure channel as a code-injection path

    Loading code at runtime that was not part of your installed app, a dex file or library downloaded after install, is one of the riskier things an Android app can do. The loaded code is not reviewed, not scanned, and if it arrives over an insecure channel it can be tampered with, which turns dynamic loading into a code-injection path. Google Play also restricts apps that update or extend themselves with executable code outside the store's own update mechanism. The safer default is to ship your code in the app. Here is what dynamic code loading is, why it is risky, and how to handle it.

    Short answer

    Dynamic code loading is running executable code that was not included in your installed app, for example loading a dex or JAR file with DexClassLoader, or a native library, fetched at runtime. Per Android's guidance, this is risky because the loaded code is not part of what was reviewed or scanned, and if it is fetched over an insecure channel or from an untrusted source it can be tampered with, becoming a code-injection path. Google Play also restricts apps that modify or extend themselves with code delivered outside Google Play's update mechanism. The safe default is to ship code in the app; if you must load it dynamically, load only trusted code over HTTPS with integrity verification.

    What you should know

    • Dynamic loading runs code not in the install: fetched at runtime.
    • The loaded code is unreviewed: not scanned or vetted like the shipped binary.
    • It can be a code-injection path: if fetched insecurely or from an untrusted source.
    • Play restricts self-updating code: outside Google Play's update mechanism.
    • Shipping code in the app is the safe default: avoid dynamic loading where you can.

    What is dynamic code loading?

    It is loading and executing code at runtime that was not bundled into the app at install. On Android, this typically means using a class loader like DexClassLoader to load a dex or JAR file, or loading a native library, that the app obtained after installation, often downloaded from a server. Developers reach for it to deliver plugins, update logic without a store release, or reduce initial app size, but it fundamentally changes the app's behavior with code that did not go through the review and scanning that the shipped binary did. That is the crux: whatever runs in your app should be code you control and have vetted, and dynamically loaded code, especially fetched at runtime, breaks that assumption. So dynamic code loading is a capability with real uses and real risks, and the risk is proportional to how much you trust the source and channel of the loaded code.

    Why is dynamic code loading risky?

    Because unreviewed code from an untrusted source or channel can be malicious or tampered. The table lists the risks.

    RiskWhy it matters
    Code injectionCode fetched over an insecure channel can be modified in transit
    Untrusted sourceLoaded code may be malicious or compromised
    No review or scanningThe dynamic code did not go through your normal checks
    Larger attack surfaceRuntime-loaded code expands what can go wrong
    Policy violationSelf-updating with external code can break Play policy

    The most serious is code injection: if your app downloads a dex or library over an insecure connection, an attacker on the network can substitute their own code, which then runs with your app's permissions. Even from your own server, the loaded code bypasses the static review and scanning your shipped binary received. And Google Play restricts apps that modify, replace, or update themselves using a method other than Google Play's update mechanism, so dynamically delivering executable code can also be a policy problem.

    How do you handle it safely, or avoid it?

    Prefer shipping code in the app, and if you must load dynamically, only trusted code over HTTPS with integrity verification. The safest approach is to include your code in the app and update it through normal store releases, avoiding dynamic loading of executable code entirely, which sidesteps both the security and policy risks. Where a genuine need exists, load only from a source you control over HTTPS so it cannot be tampered in transit, verify the integrity of the loaded code, such as a signature or checksum you check before executing it, and never load code from an untrusted or user-supplied source. Do not use dynamic loading to change your app's behavior in ways that would bypass app review or violate the rule against self-updating with external code. The principle is that any code your app runs should be code you trust and have verified, so dynamic loading must come with the same assurances as your shipped binary, or it should not happen.

    What to watch out for

    The first trap is downloading and loading a dex or library over an insecure channel, which lets an attacker inject code; use HTTPS and verify integrity. The second is loading code from an untrusted or user-supplied source, which can run malicious code with your app's permissions. The third is using dynamic loading to self-update outside the store, which can violate Google Play policy. A pre-submission scan such as PTKD.com (https://ptkd.com) reads the compiled APK or AAB against OWASP MASVS and can surface dynamic code-loading patterns in your build, so you can confirm your app is not loading unreviewed code unsafely. The loading logic you control in the app.

    What to take away

    • Dynamic code loading runs executable code not bundled in the installed app, such as a dex or library fetched at runtime, which is unreviewed and can be a code-injection path.
    • Code fetched over an insecure channel can be tampered with, and Google Play restricts self-updating with code delivered outside its update mechanism.
    • Prefer shipping code in the app; if you must load dynamically, use only trusted sources over HTTPS with integrity verification, and never load untrusted code.
    • Use a pre-submission scan such as PTKD.com to surface dynamic code-loading patterns and confirm your app is not loading unreviewed code unsafely.
    • #android
    • #dynamic-code-loading
    • #dexclassloader
    • #code-injection
    • #owasp-masvs
    • #app-security
    • #google-play

    Frequently asked questions

    What is dynamic code loading on Android?
    It is loading and executing code at runtime that was not bundled into the app at install, typically using a class loader like DexClassLoader to load a dex or JAR file, or a native library, that the app downloaded after installation. Developers use it for plugins, updating logic without a store release, or reducing app size, but it runs code that did not go through the review and scanning the shipped binary did, which is the source of the risk.
    Why is dynamic code loading risky?
    Because unreviewed code from an untrusted source or channel can be malicious or tampered. The most serious risk is code injection: if your app downloads a dex or library over an insecure connection, an attacker on the network can substitute their own code, which runs with your app's permissions. Even from your own server, the loaded code bypasses your normal static review and scanning, and self-updating with external code can also violate Google Play policy.
    Does Google Play allow dynamic code loading?
    It restricts it. Google Play's policy bars apps from modifying, replacing, or updating themselves using a method other than Google Play's update mechanism, so dynamically delivering executable code to change your app can be a policy problem, in addition to the security risk. Interpreted code and configuration are treated differently from delivering new executable behavior. The safest path for compliance and security is to ship your code in the app and update through normal store releases.
    How do I load code dynamically more safely?
    Avoid it where you can by shipping code in the app. Where a genuine need exists, load only from a source you control over HTTPS so the code cannot be tampered in transit, verify its integrity with a signature or checksum you check before executing it, and never load code from an untrusted or user-supplied source. Do not use dynamic loading to change behavior in ways that bypass review. Any code your app runs should be trusted and verified to the same standard as the shipped binary.
    How do I find dynamic code loading in my app?
    Scan the build. A pre-submission scan such as PTKD.com reads the compiled APK or AAB against OWASP MASVS and can surface dynamic code-loading patterns, so you can confirm your app is not loading unreviewed code unsafely before you ship. If it flags dynamic loading, the fix is to ship the code in the app instead, or, where loading is genuinely needed, ensure it comes from a trusted source over HTTPS with integrity verification.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free