Three kinds of secret, told apart by how they behave
The word secret covers several different things in a mobile app, and the difference matters more than the label.
An embedded credential is a fixed string compiled into the application. An API key issued to the application, a client identifier and a shared secret used for a request signature are all of this kind. The value is the same on every install, so it can be recovered once and copied.
A derived credential is computed at run time from data the app already holds. A signing key assembled from several constants, or a value produced by a key derivation function over a device value, belongs here. Recovering the inputs is necessary, but the raw inputs alone do not give a client a working value unless the derivation is reproduced as well.
A session credential is issued by the server during a login or a handshake and expires. It appears in memory and in traffic but is not part of the application at all.
Testing which kind you have is straightforward. Restart the app and watch whether the value changes. If it does, it is a session credential. If it stays the same across installs and devices, it is embedded. If it stays the same on one device but differs on another, it is derived from device state.
Where embedded values sit in a compiled Flutter build
A release Flutter app compiles its Dart code ahead of time, and the constants that code uses live in the compiled snapshot inside the application's shared library. A literal string is not stored as a language-level constant with a name attached. It is data placed where the code can load it, which means the string is present in the library as bytes.
That makes a byte-oriented search the most productive first step. Values worth looking for include host names, path fragments that look like a versioned API, header names, JSON field names, and strings in the shapes that credentials commonly take: long base64 blocks, hexadecimal runs of fixed length, PEM blocks, and the UUID form that many client identifiers use.
The same library also carries strings that belong to the Flutter engine and to the standard libraries, so a search returns a large amount of noise. Filtering by context helps. A credential that is used to build a header usually sits near the header name. A signing secret is usually near the name of the algorithm or the parameter it feeds.
Values that only exist in memory
Some credentials never appear as a complete literal because the app assembles them at run time. The stored form is fragments plus the code that joins them, and the assembled value exists only in the heap while the app runs.
A memory inspection at the point where the value is used is the way to see it. The observable moments are the same as in any client: the request builder, an HTTP interceptor, or the transport layer. Reading the value at one of those points gives you the assembled credential along with the surrounding state that produced it, which is often more useful than the string on its own.
This is also the moment to check whether the value is bound to anything else. A token that is valid only when particular headers match, or only from the device that requested it, will fail outside the app even when the string is copied exactly. The relevant checks are described in device farm isolation and in token generation from an APK.
Whether the extracted value keeps working
An embedded credential that a server can revoke is a temporary asset. Before building a client around one, establish whether the server can rotate it and how the app would learn about a new value. If the app fetches its configuration at start-up, the credential is effectively delivered at run time and may already be rotating. If the value is fixed in the build, a rotation requires an app update, which bounds how often it can happen.
The stable parts of a reconstructed client are the protocol and the request shape. Credentials should sit in configuration rather than in code, so a change on the server side does not require changing the client. Runtime derived keys covers the case where the credential is produced rather than stored, and Flutter API reverse engineering covers the wider task of turning a Flutter app into a callable client.
Related work
Reviewed 28 September 2026 · SReverse research desk