Listen to this Post

Introduction:
A recent spate of unauthorized push notifications across multiple major Turkish applications, including İşbankası’s Nays, Fenerbahçe, and LCW, highlights a critical and recurring security failure. The incident, suspected to be caused by exposed backend API keys, demonstrates how a single misconfiguration can be weaponized to spam millions of users, eroding trust and damaging brand reputation in an instant.
Learning Objectives:
- Understand the technical cause and impact of exposing push notification service credentials.
- Learn how to identify and securely manage API keys and secrets within your infrastructure.
- Implement best practices for hardening your notification services against unauthorized access.
You Should Know:
1. Identifying Exposed Firebase Cloud Messaging (FCM) Keys
A common culprit in push notification hacks is an exposed FCM Server Key. This key should never be embedded in client-side code (e.g., mobile apps, JavaScript). Attackers can easily extract it from decompiled APKs or browser network traffic.
Step-by-step guide:
To check if your Android app exposes its FCM key, you can use a tool like `apktool` to decompile it and search for the string.
Decompile an APK file apktool d your_app.apk Search for FCM or Google API key strings within the decompiled code grep -r "AAAA" your_app_decoded_directory/ grep -r "key=" your_app_decoded_directory/ grep -r "google" your_app_decoded_directory/ | grep "api"
What this does: The `apktool` command decompiles the Android application package into readable files. The `grep` commands then search for patterns indicative of an API key. Finding a key in the client-side code is a severe misconfiguration.
2. The Critical `curl` Test: Validating Key Permissions
Once an attacker has a key, they can test its permissions using a simple `curl` command to the FCM API. This simulates the attack and confirms the key is valid for sending messages.
Step-by-step guide:
curl -X POST --header "Authorization: key=AAAAYOUR_EXPOSED_KEY" \
--Header "Content-Type: application/json" \
https://fcm.googleapis.com/fcm/send \
-d '{"to":"/topics/all","data":{"message":"This is a test hack."}}'
What this does: This command sends a POST request to the FCM service. The `Authorization` header contains the stolen key. If the key is valid and has not been restricted, the message will be sent to all devices subscribed to the topic “all”.
3. Securing Keys with Environment Variables and Vaults
Never hardcode secrets. Instead, use environment variables and secret management solutions like HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault. This keeps keys out of your codebase.
Step-by-step guide (Example for a Node.js backend):
// BAD: Key hardcoded in source const FCM_KEY = 'AAAA...'; // GOOD: Key loaded from environment variable const FCM_KEY = process.env.FCM_SERVER_KEY; // To run your app: FCM_SERVER_KEY=your_real_key node app.js
What this does: By using an environment variable, the secret is injected at runtime by your server’s environment or orchestration tool (e.g., Kubernetes Secrets), preventing it from being exposed in your version control system.
4. Restricting API Keys on Google Cloud Platform
If you must use a key, restrict its usage to only the APIs and IP addresses that require it. This limits the damage if the key is exposed.
Step-by-step guide (GCP Console):
- Navigate to Google Cloud Console > APIs & Services > Credentials.
- Select the API key you use for FCM.
- Under “Application restrictions,” set it to restrict to your server’s IP addresses.
- Under “API restrictions,” restrict the key to only the “Firebase Cloud Messaging API.”
What this does: These restrictions ensure that even if the key is stolen, it cannot be used from an unauthorized IP address or to access any other Google API, drastically reducing its utility to an attacker.
5. The Superior Alternative: Using Authorized Service Accounts
For server-to-server communication, using a service account with limited IAM permissions is more secure than a static API key.
Step-by-step guide (Using a Service Account JSON key):
1. Create a service account in GCP IAM & Admin with the role "Firebase Cloud Messaging Admin".
2. Download the JSON key file and store it securely on your server.
3. Use the Google Auth library in your code.
const {GoogleAuth} = require('google-auth-library');
const auth = new GoogleAuth({
keyFile: 'path/to/service-account-key.json',
scopes: 'https://www.googleapis.com/auth/firebase.messaging',
});
// The client will automatically obtain and use an access token.
What this does: Service accounts provide short-lived, automatically rotated access tokens instead of a static, permanent key. This follows the principle of least privilege and is inherently more secure.
6. Implementing Push Notification Topic Security
Sending a message to `/topics/all` is a massive red flag. Implement topic subscription security by using instance ID (IID) tokens and only allowing users to subscribe to appropriate topics from your backend.
Step-by-step guide (Backend validation):
// Pseudocode for secure topic subscription
app.post('/subscribe/:topic', authenticateUser, (req, res) => {
const user = req.user;
const topic = req.params.topic;
// Validate the user is allowed to subscribe to this topic
if (!isUserAllowedToSubscribe(user, topic)) {
return res.status(403).send('Forbidden');
}
// If valid, call the FCM admin SDK to subscribe the device token
admin.messaging().subscribeToTopic(user.deviceToken, topic)
.then((response) => res.send(response))
.catch((error) => res.status(500).send(error));
});
What this does: This ensures a user cannot arbitrarily subscribe to any topic, especially broad ones like “all”. The backend logic enforces business rules around subscriptions.
7. Auditing and Rotating Exposed Keys
If you suspect a key has been exposed, you must immediately rotate it. All previous keys should be revoked.
Step-by-step guide (Rotating FCM Key in Firebase Console):
- Go to Firebase Console > Project Settings > Cloud Messaging.
- Under “Server keys,” you will see your current keys.
- Click the overflow menu (three dots) next to the key and select “Delete.”
4. Generate a new server key.
- Immediately update your backend services with the new key, using your secure method (e.g., environment variable, vault).
What this does: Deleting the old key instantly invalidates it, preventing any further unauthorized use. The new key must then be deployed securely to your backend infrastructure.
What Undercode Say:
- The Human Firewall is Failing: This is not a complex zero-day exploit. It’s a fundamental misconfiguration that keeps happening. It points to a critical gap in security training and code review processes for developers.
- Shift Security Left: Security checks for hardcoded secrets must be integrated into the CI/CD pipeline. Tools like
git-secrets,truffleHog, and GitHub’s built-in secret scanning are non-negotiable for modern development.
This incident is a stark reminder that the most devastating breaches often stem from the simplest oversights. While companies focus on advanced threat protection, they leave the back door wide open with practices like embedding keys in client-side code. The solution is a cultural shift that prioritizes security fundamentals—secret management, least privilege, and proactive auditing—over reactive measures. The tools and knowledge to prevent this are readily available; the failure is in their consistent implementation.
Prediction:
The recurrence of these low-sophistication, high-impact attacks will force a major evolution in DevSecOps practices. We will see the widespread mandatory adoption of automated secret scanning in CI/CD pipelines, not as a best practice but as a compliance requirement. Furthermore, cloud providers will likely begin to deprecate static API keys in favor of more secure, short-lived certificate-based authentication by default, making the old, insecure way of doing things impossible.
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Sezersanlikan Nays – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


