📋 What Is It?
Client Code Quality is the category for code-level implementation defects inside the mobile client itself that turn into security problems - memory-safety bugs, unchecked input handling, misuse of dangerous APIs, and sloppy error handling in the app you ship to the device.
The distinction matters. Most mobile risks are about what the app does with data; M7 is about how the code is written. Two apps can implement the same feature - one parses a deep link with a bounds-checked, type-safe routine, the other copies attacker-controlled bytes into a fixed native buffer with strcpy. Same feature, same data flow, but only the second crashes, corrupts memory, or executes attacker code when fed a hostile input.
⚠️ Common Exploits
- Buffer Overflows:
strcpy/sprintf/memcpywith an attacker-controlled length - Format String Bugs: user data passed as the format argument
- Use-After-Free / Double-Free: lifetime errors in native code
- Unsafe Deserialization: arbitrary object graphs decoded from untrusted bytes
- Unvalidated Deep Links & IPC: intent extras and URLs trusted as-is
- Integer Overflow: a size calculation wraps and under-allocates
- Unhandled Errors: null dereference or uncaught exception → crash-to-DoS
- Dangerous WebView APIs:
addJavascriptInterfaceon legacy targets
🔴 Attack Flow
↓
2. Fuzz each with oversized, malformed, and unexpected-type values
↓
3. Watch for crashes, tombstones, and memory-corruption signatures
↓
4. Triage a crash into a controllable primitive in native code
↓
5. IMPACT: Denial of service - or code execution inside the app's sandbox!
❌ Vulnerable Code
✅ Secure Code
✓ Prevention Checklist
- Validate every untrusted input at the client boundary: type, length, range, format
- Treat deep links, IPC extras, files, and server responses as hostile
- Avoid
strcpy,sprintf,gets; use length-limited APIs - Check arithmetic for overflow before allocating or copying
- Deserialize into known types only; never decode arbitrary object graphs
- Prefer memory-safe languages (Kotlin/Swift/Rust) for parsing untrusted data
- Handle errors explicitly and fail closed - never swallow an exception
- Enable compiler and linker hardening; run ASan/UBSan in CI
- Fuzz every input parser as part of the build
- Zero secrets in memory once used; avoid leaving them in long-lived buffers
- Enforce static analysis and code review on all native code
🔍 Detection & Tools
Static & Build:
Dynamic:
How to Test:
- Fuzz deep links, intent extras, and file imports with oversized inputs
- Send malformed server responses to the app's parsers
- Run debug builds with ASan/UBSan and exercise every input path
- Review all JNI/native code for unbounded copies and format strings
- Check crash logs for repeatable, attacker-triggerable faults
🌍 Real-World
These are documented incident classes - recurring patterns rather than single CVEs.
- Media and image parsers: memory-corruption bugs in native decoding libraries reached by a crafted file or message attachment.
- Deep-link handlers: unvalidated URLs loaded into WebViews leading to local file access or script execution in the app's context.
- Deserialization gadgets: untrusted serialized data decoded into arbitrary classes, giving code execution.
- Crash-to-DoS: a malformed push payload or IPC message that reliably kills the app on receipt.
- Legacy WebView bridges:
addJavascriptInterfaceon old API levels exposing reflection to remote pages.
📌 Quick Tips
- DO NOT copy untrusted bytes into fixed buffers
- DO NOT pass user data as a format string
- DO NOT deserialize arbitrary types
- DO validate every client-side input boundary
- DO fuzz parsers and run sanitizers in CI
- DO prefer memory-safe languages for parsing
📜 Compliance
Related Standards:
- OWASP Mobile Top 10 2016 - M7
- Maps to M4:2024 Insufficient Input/Output Validation
- OWASP MASVS CODE-1 … CODE-4
- CWE-120 Buffer Copy without Checking Size of Input
- CWE-134 Uncontrolled Format String
- CWE-416 Use After Free
- CWE-502 Deserialization of Untrusted Data