Move the keystore path and passwords out of build.gradle into a separate keystore.properties file in the project root, load that file in the build script, and keep it out of version control. In CI, supply the same values from the secret store instead of a file in the repo.
The problem
Google's documentation says Android Studio stores signing information in plain text in the build.gradle files. A build file is committed, reviewed, copied into forks, and printed in logs. Passwords there are easy to leak, and once in git history they are hard to remove.
Google recommends a simple pattern: put the values in a properties file in the project root, load that file in the build script, and reference its values in the signing configuration. The properties file stays out of source control.
The pattern
Create a file named keystore.properties in the project root:
storePassword=changeme
keyPassword=changeme
keyAlias=upload
storeFile=/path/to/upload-keystore.jks
Add the filename to your ignore file so it is never committed. Then load it in the module build script and point the signing configuration at those values. Google's article shows the Groovy and Kotlin forms of this step, so copy from there for your Gradle version.
What counts as a secret here
| Item | Secret? | Notes |
|---|---|---|
| Keystore file | Yes | Contains the private key |
| Store password | Yes | Unlocks the keystore |
| Key password | Yes | Unlocks the key |
| Key alias | Low risk | Identifies the key, not a credential |
| Certificate fingerprint | No | Public, used to register with APIs |
Treat the first three as credentials. Google's advice for keys you manage yourself is to select strong passwords for the keystore and key, not to give or lend anyone your private key, and to keep the keystore file in a safe, secure place.
In CI
A local properties file works on a laptop, but a CI runner has no such file. Use your CI system's secret store for the keystore (often as a Base64 encoded value that is decoded at build time), the passwords, and the alias. Write them to a temporary properties file on the runner, or pass them as environment variables that the build script reads.
GitHub's documentation on secrets gives two relevant cautions. Base64 only converts binary to text and is not a substitute for encryption. And avoid passing secrets between processes on the command line where you can, since command lines may be visible to other users.
A short checklist
- The properties file name is in the ignore file.
- No signing password appears in any committed Gradle file.
- A search of git history finds no old keystore or password. If one exists, rotate it.
- CI reads the keystore and passwords from secrets, with access limited to the release job.
- Logs never print the properties file or its values.
- Someone has verified a release build can still be produced from a clean checkout.
If an old password did leak, change it and consider whether the keystore itself needs replacing. For Play App Signing, an upload key can be reset, as covered in the post on lost upload keys at /resources/blog/lost-android-upload-key-how-to-request-an-upload-key-reset.
Where Safeguard fits
Secret handling protects the signing step. Safeguard adds dependency scanning and SBOMs for what goes into the build, with a free scan at gold.safeguard.sh/scan.
Quick check
Does Android Studio store signing passwords in plain text?
Google states that Android Studio stores signing information in plain text in the build.gradle files, and recommends moving it to a properties file kept out of source control.
Is Base64 encoding a keystore enough to protect it in CI?
No. GitHub's documentation says Base64 only converts binary to text and is not a substitute for encryption. Rely on the secret store's access controls.
Sources
Last reviewed: 19 October 2026.