TL;DR: Android optimizers such as ProGuard and R8 can break apps when reflection-dependent classes are renamed or removed, and that debugging keep rules often requires iterative crash analysis, according to Guardsquare. Its guided workflow claims to collect the needed keep rules during instrumentation so teams can configure protection with less trial and error.
At a glance
What this is: This article explains why Android optimisation tools can break reflection-heavy code and how guided profiling can capture the keep rules needed to keep an app functional.
Why it matters: It matters to IAM and security teams because application protection controls can silently affect identity-adjacent runtime behaviour, including auth, serialization, and any code paths that depend on stable class or field names.
👉 Read Guardsquare's guidance on keep rules and guided Android configuration
Context
Android app hardening often creates a governance gap: the same optimisation that reduces code size or increases resilience can also remove or rename entities that runtime code still expects to find. In practice, reflection, serialization, and other dynamic lookup patterns are the failure points, and those failures can be hard to diagnose because the app only breaks after protection is applied.
For security and platform teams, the issue is not just build stability. It is control fidelity: protection tooling must preserve intended behaviour while still enforcing obfuscation and shrinking. Where applications use identity, authorization, or session logic through libraries and dynamic dispatch, unsupported assumptions in the build pipeline can surface as production outages rather than clean test failures.
Key questions
Q: How should teams handle reflection-heavy Android apps when using code shrinking?
A: Teams should inventory every runtime lookup path, then preserve only the classes and members those paths truly need. The safest approach is to test release-like builds early, capture failures through profiling or stack traces, and narrow keep rules until runtime behaviour remains stable without overexposing code.
Q: Why do keep rules often fail on the first attempt in protected Android builds?
A: They fail because static analysis cannot always infer which symbols are accessed dynamically at runtime. Libraries may also hide reflection behind abstractions, so the first rule often fixes only the visible crash while leaving other accessed members renamed or removed. Iteration or profiling is usually required.
Q: What do security teams get wrong about broad keep rules?
A: They treat broad preserve rules as a safe fallback, but those rules can weaken shrinking and obfuscation across far more code than necessary. That creates long-term security debt because the app remains functional while the protection posture becomes less precise and easier to reverse engineer.
Q: How do guided profiling workflows reduce risk in mobile app hardening?
A: They reduce risk by observing real execution paths and collecting keep rules from actual runtime behaviour instead of relying on guesswork. That gives teams a more complete starting point, provided they profile all critical journeys and still review the collected rules for unnecessary breadth.
Technical breakdown
Why reflection breaks after code shrinking
Optimisers such as ProGuard and R8 rename, merge, or remove classes and members that appear unused. Reflection depends on stable runtime names, so when code looks up a class, method, or field dynamically, the lookup can fail after obfuscation. Libraries can hide this dependency because the application code may not call reflection directly. The key technical issue is that static analysis can only infer so much. Once a dynamic access path escapes the analyser's model, the build needs explicit keep rules to preserve the exact symbols that runtime code expects.
Practical implication: Map every reflection or serialization path to explicit keep rules before shipping a protected build.
What consumer rules do and do not protect
Consumer rules are library-provided keep rules that ship with dependencies such as Moshi. They protect the library's own internals from being broken by shrinking or obfuscation, but they do not automatically protect application-specific classes used by that library. That distinction matters because a library can appear to work while the app's own model classes are still renamed or stripped. In other words, dependency rules are not a substitute for application-level configuration, especially when the library constructs objects through reflection or inspects fields by name.
Practical implication: Review dependency-supplied rules separately from app rules and test the combined effect in a release-like build.
How guided profiling changes keep rule discovery
Guided workflows move rule discovery from repeated crash analysis into an instrumentation phase. The app is run in an instrumented build, runtime reflection paths are observed, and the tool collects the keep rules needed to preserve those paths. The protection phase then reuses the collected rules when building the hardened APK. This changes the engineering problem from guesswork to observation. The remaining limitation is coverage: if teams do not exercise the right screens or flows during profiling, the collected rules will be incomplete.
Practical implication: Profile all critical user journeys and admin paths before relying on automatically collected keep rules.
NHI Mgmt Group analysis
Keep-rule drift is a configuration governance problem, not just a build issue. The article shows that app protection tools can invalidate runtime assumptions when dynamic code paths depend on names that obfuscation changes. That is a governance problem because teams must control which entities remain stable, why they remain stable, and who verifies that decision across release cycles. The practical lesson is to treat keep rules as security-sensitive configuration, not as one-off debugging artefacts.
Dynamic runtime behaviour creates an identity-adjacent control surface. Reflection, serialization, and object reconstruction often sit close to authentication, session handling, and policy enforcement in mobile applications. When those paths fail, the impact is not only crashes but also broken trust in runtime control flow. For identity and access teams, the relevant question is whether application hardening preserves the logic that governs access and token handling. The conclusion is that protection workflows must be validated against business-critical runtime paths.
Guided profiling is a stronger operating model than iterative crash repair for complex apps. Repeated rebuild-and-fix loops scale poorly when code paths are numerous and library behaviour is opaque. An instrumentation-driven workflow gives teams a more defensible starting point because it captures evidence from real execution rather than inference alone. That aligns with modern secure build governance, where control effectiveness depends on observing production-like behaviour before enforcement. The practitioner conclusion is to prefer profiled configuration over broad, permanent keep exceptions.
Overly broad preserve rules create security debt. The article notes that broad rules can keep an app functional, but they also reduce the effectiveness of shrinking and obfuscation. That trade-off matters because protection controls should be as narrow as the runtime requires, not wider. In identity-heavy apps, preserving too much code can expand the attack surface that obfuscation was intended to reduce. The right discipline is to narrow rules until the runtime dependency is satisfied and no further.
Protected builds need test coverage that mirrors real feature use. Automatic rule collection only works if profiling reaches the flows that exercise reflection and dynamic access. That means release validation should include the screens, paths, and edge cases most likely to touch runtime lookup. Security teams should treat incomplete profiling as an assurance gap, because a clean build can still hide an unobserved crash path in production.
From our research:
- Only 5.7% of organisations have full visibility into their service accounts, according to Ultimate Guide to NHIs.
- 71% of NHIs are not rotated within recommended time frames, increasing the risk of compromise over time.
- For the broader control problem: Review the Ultimate Guide to NHIs for lifecycle, visibility, and offboarding controls that reduce hidden access paths.
What this signals
Configuration drift will matter more than build success metrics. As mobile apps become more heavily protected, teams should measure whether hardening changes preserve dynamic runtime behaviour, not just whether the APK compiles. That means release validation needs a tighter link between engineering, app security, and identity-sensitive control paths such as login, token handling, and authorization.
Keep rules are effectively a policy layer for runtime stability. When those rules are too broad, the protection layer leaks value by preserving more symbols than necessary. When they are too narrow, the app breaks under real user flows. Teams should treat the balance as a governance decision and tie it to test coverage, release gates, and post-build verification.
Identity-heavy mobile apps need stronger runtime assurance. If an application supports authentication, session management, or credential handling, its protection workflow should be validated with the same care as its access controls. The operational signal is simple: if profiling does not cover the flows that matter, the build is not yet ready for hardened release.
For practitioners
- Inventory dynamic lookup paths Identify every use of reflection, serialization, runtime class loading, and name-based field access in the app and its libraries before enabling aggressive shrinking.
- Separate library rules from application rules Review consumer rules supplied by dependencies and verify that they do not mask missing app-specific keep rules during release builds.
- Profile real user journeys before protection Run instrumented builds through login, onboarding, admin, and data-entry paths so automatic rule collection captures the flows most likely to fail.
- Avoid permanent broad keep exceptions Use broad rules only as a short diagnostic step, then narrow them to the smallest class and member set that preserves runtime behaviour.
Key takeaways
- The article shows that Android optimisation can break reflection-dependent code unless keep rules preserve the exact runtime symbols that dynamic paths expect.
- Guided profiling shifts keep-rule discovery from repeated crash debugging to observed execution, but only if teams exercise the right app journeys.
- Protection quality depends on narrow, tested configuration, because overly broad preserve rules can trade stability for weaker obfuscation.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
NIST CSF 2.0, NIST SP 800-53 Rev 5 and CIS Controls v8 set the technical controls, while ISO/IEC 27001:2022 define the regulatory obligations.
| Framework | Control / Reference | Relevance |
|---|---|---|
| NIST CSF 2.0 | PR.IP-1 | The article is about preserving secure configuration through build and release changes. |
| NIST SP 800-53 Rev 5 | CM-3 | Change control matters when optimisation alters code structure and runtime symbols. |
| CIS Controls v8 | CIS-16 , Application Software Security | Application hardening and release validation are central to this keep-rule problem. |
| ISO/IEC 27001:2022 | A.8.29 | Secure coding and change control are relevant where build tooling affects application integrity. |
Validate protected builds against PR.IP-1 so hardening does not break approved runtime behaviour.
Key terms
- Keep Rule: A keep rule tells an optimiser or obfuscator which classes, methods, or fields must not be renamed, removed, or merged. It preserves runtime symbols that code depends on, especially when reflection, serialization, or framework lookup uses names rather than explicit references.
- Consumer Rules: Consumer rules are keep rules shipped with a library so its own internals continue to function after optimisation. They do not automatically protect application-specific types that the library uses at runtime, so teams still need to verify their own configuration separately.
- Reflection: Reflection is a runtime mechanism that lets code inspect or access classes, methods, or fields by name. It is useful for flexible frameworks, but it becomes fragile when obfuscation changes the names or structure that the runtime lookup expects.
- Guided Workflow: A guided workflow is an instrumentation-driven method for collecting configuration rules from real app usage before applying protection. It reduces guesswork by observing dynamic behaviour during profiling, then reusing the captured rules in the hardened build.
What's in the full article
Guardsquare's full article covers the operational detail this post intentionally leaves for the source:
- Step-by-step debugging of the Moshi reflection crash and how each keep rule changes the stack trace.
- The exact guided workflow sequence for instrumentation, profiling, and protection in DexGuard.
- How the tool flags the User class after automatic rule collection and what that warning means operationally.
- The command-level workflow used to generate and protect the APK in a release-like pipeline.
Deepen your knowledge
NHI Foundation Level course, the industry's only accredited NHI security programme, covers NHI governance, workload identity, and secrets management for practitioners building secure access controls. It helps identity and security teams connect governance discipline to the systems that depend on stable credentials and runtime behaviour.
Published by the NHIMG editorial team on August 18, 2026.
NHI Mgmt Group — the independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org