/ANDROID · 2026-08-21
SSL pinning is a client opinion
The app refuses TLS unless the cert or SPKI matches a list. That is a client trust boundary we name. We do not ship unpin kits.
Pinning means the client will not complete TLS unless the peer certificate (or its SPKI hash) is on a list the app shipped. Casual intercept on a stock build fails. That is useful. It is also only a statement about this binary, as shipped, on a device that still runs it.
Authorized APK and a lab device named in the letter. We map where the pin lives. We do not publish Frida unpin scripts, TrustManager replacements, or “objection recipes.”
Where it actually lives
network_security_config.xml
Android’s own file. apktool shows it. Pins, debug overrides, cleartext. If debug-overrides still allow user CAs in the release variant, the pin is a suggestion. Write the filename and the domain list. That is the finding shape.
OkHttp CertificatePinner / similar Java
jadx: a list of SPKI hashes next to hostnames. Honest, easy to screenshot, easy to go stale when the CDN rotates. We copy the hosts, not a bypass.
Custom TrustManager / HostnameVerifier
Often “pinning” that is actually return true in debug leftover. Read it. If it accepts anything, say so. If it compares to a baked-in cert in assets, name the asset.
Native
BoringSSL verify hooks, a .so that never uses the Java stack. jadx will look unpinned. The traffic still dies in Charles. Then Ghidra on the .so — same native desk as everything else. Do not declare “no pinning” from Java alone.
Combination on the desk
apktool → res/xml/network_security_config.xml
jadx → CertificatePinner, TrustManager, hostname lists
lib/*.so → only if Java has no TLS and traffic still refuses intercept
lab device → confirm: stock build fails intercept, or it does not
server → does a build without the pin still get tokens?
Pinning that the API does not notice is theater. If the engagement asks “does the broker still run when the Java layer is lied to,” that test stays in the report. The method does not go on this site.
Adjacent controls
- Attestation is separate. A pinned client on a rooted phone is still that client. See keybox / Play Integrity.
- A pin does not prove the request body came from unmodified code.
- The server still has to refuse old, debug, or sideloaded builds.