A $2,000 API Key: Unauthorized Access to Paid Medical Transcription

Severity: High
Bounty: $2,000
Retest Reward: $150
Total Awarded: $2,150
Program: Private Program
Platform: HackerOne
This finding started with a familiar Android testing problem:
What secrets were shipped inside the production APK?
While decompiling an explicitly in-scope Android application for a healthcare platform, I found a live Deepgram API key hardcoded inside a generated BuildConfig class.
The key was not an unused development credential.
It authenticated successfully, exposed internal account and project metadata, and allowed me to submit audio directly to Deepgram’s paid medical transcription service.
Anyone who downloaded the APK could extract the same credential and consume the company’s production transcription resources.
The program eventually rated the issue High because sufficient abuse would force them to revoke the shared token, leaving mobile clients in a degraded state.
Finding the Key
I began with static analysis of the production Android APK.
After decompiling the application, I searched the source for API keys, authorization headers, third-party service URLs, and generated configuration values.
Inside a BuildConfig class, I found:
public static final String DEEPGRAM_API_KEY = "[REDACTED]";
The class path was similar to:
[redacted.package].tracker.BuildConfig
This was immediately interesting for two reasons.
First, the value was clearly named as an API key.
Second, Deepgram provides cloud-based speech-to-text services, including specialized medical transcription models.
The application appeared to use the service for an AI-powered transcription feature.
Because the key was embedded in the APK, it was available to anyone capable of downloading and decompiling the application.
No root access, runtime instrumentation, or account authentication was required to extract it.
The exposure path was simply:
Download APK
↓
Decompile application
↓
Inspect BuildConfig
↓
Recover production API key
Confirming That the Key Was Live
Finding something that looks like an API key is not enough.
It could be expired, restricted, disabled, or left over from an old build.
I first tested the credential against Deepgram’s token information endpoint:
curl -s -X GET "https://api.deepgram.com/v1/auth/token" \
-H "Authorization: Token [REDACTED]"
The request succeeded.
The response returned metadata associated with the credential, including:
{
"subject": "[REDACTED]",
"email": "[REDACTED]",
"scopes": [
"account:write"
],
"accessor": "[REDACTED]",
"created": "[REDACTED]"
}
This confirmed that:
the key was active
it was associated with an internal account
it carried an
account:writescopeit had not been limited to the Android application itself
At this point, I had confirmed a live production credential.
But token validation alone did not prove the most important part of the report:
Could an attacker actually use the company’s paid transcription service?
Proving Unauthorized Paid Service Usage
To demonstrate real-world impact without processing sensitive or third-party audio, I generated a two-second WAV file locally.
The file contained only a synthetic tone:
ffmpeg \
-f lavfi \
-i sine=frequency=1000:duration=2 \
-ac 1 \
-ar 16000 \
test.wav
I then submitted it to Deepgram’s transcription endpoint using the extracted key:
curl -X POST \
"https://api.deepgram.com/v1/listen?model=nova-3-medical&mip_opt_out=true" \
-H "Authorization: Token [REDACTED]" \
-H "Content-Type: audio/wav" \
--data-binary @test.wav
The service accepted the request and processed the file.
A shortened version of the response looked like:
{
"metadata": {
"duration": 2.0,
"models": [
"medical-nova-3"
]
},
"results": {
"channels": [
{
"alternatives": [
{
"transcript": "[MODEL OUTPUT]",
"confidence": 0.43
}
]
}
]
}
}
The quality of the transcript was irrelevant because the input was only a generated tone.
The important result was that the request succeeded.
The exposed key allowed an unaffiliated user to:
Submit attacker-controlled audio
↓
Use the production medical model
↓
Consume billable transcription resources
There was no additional application-level authentication.
Possession of the key was enough.
Access to Internal Project Metadata
The credential also allowed me to enumerate Deepgram projects associated with the account.
I sent:
curl -X GET "https://api.deepgram.com/v1/projects" \
-H "Authorization: Token [REDACTED]"
The response contained an active production project:
{
"projects": [
{
"project_id": "[REDACTED]",
"name": "[REDACTED]",
"mip_opt_out": true
}
]
}
This provided:
an internal project identifier
the project name
project-level configuration metadata
confirmation that the key was connected to the company’s active environment
I did not attempt destructive actions or make changes to the account.
The demonstrated access was limited to validating the credential, processing a small synthetic audio file, and retrieving project metadata.
The Initial Impact
The immediate risk was direct financial abuse.
An attacker could automate requests against the transcription endpoint and submit audio using the company’s key.
The attack would look like:
Extract API key from APK
↓
Send repeated transcription requests
↓
Consume paid API resources
↓
Charges billed to the affected company
Because the key was distributed inside the mobile application, rotating it without changing how the application authenticated would only provide a temporary fix.
Any replacement key embedded in a future APK could be extracted again.
There was also an availability concern.
If abuse became significant, the company would need to revoke the shared credential immediately.
That would stop the attacker, but it could also interrupt the transcription feature for legitimate mobile users until the application was updated or switched to a fallback.
That consequence later became central to the program’s severity assessment.
An Unexpected Reproduction Problem
The initial HackerOne review passed the preliminary analyst stage.
The analyst then attempted to reproduce the issue using an APK provided directly by the program.
They could not find the key.
They asked me where I had obtained the application and noted that the behavior was not present in the program-supplied file.
After comparing both APKs, the reason became clear.
I had analyzed a newer public-distribution build obtained from a public APK mirror.
The program-provided HackerOne build was an older, specially labeled version.
The comparison looked like:
Newer public-distribution build
↓
Hardcoded Deepgram key present
while:
Older program-provided build
↓
Hardcoded Deepgram key not present
The two parties were analyzing different versions of the same application.
I explained that the issue reproduced in the newer public build but not in the older HackerOne-specific build.
That accounted for the conflicting results.
The report was then moved to pending program review while the analyst discussed it directly with the company.
Why the Source of the APK Mattered
This part of the report highlighted an important mobile testing problem.
A program may provide researchers with a dedicated APK, but that file is not always identical to the current production version distributed to users.
Possible differences include:
older application code
disabled production integrations
removed third-party credentials
testing-only configuration
different build flavors
separate signing or release pipelines
In this case, testing only the program-provided APK would have missed the vulnerable production build.
The affected credential was shipped in the newer version available to real users.
The key question was not simply:
Does the HackerOne APK contain the secret?
It was:
Is the secret present in an in-scope production application distributed publicly?
Once the version difference was documented, the program was able to reproduce and assess the actual issue.
Program Assessment
The program increased the severity from Medium to High, with a CVSS score of 7.3.
Their explanation focused on availability.
They noted that sufficient abuse would force them to revoke the token immediately.
Revocation would leave the mobile application in a partially degraded state because the affected feature would fall back to on-device transcription, which provided noticeably lower quality.
The operational consequence was therefore:
API key abuse
↓
Unexpected usage or financial cost
↓
Emergency token revocation
↓
Cloud transcription becomes unavailable
↓
Mobile clients fall back to lower-quality processing
The issue was not only about an attacker spending someone else’s API credits.
The credential was part of a production feature used by the mobile application.
Abusing or revoking it affected legitimate service delivery.
The report was awarded a $2,000 bounty.
The Fix
The company revoked the exposed API key.
I was invited to perform a paid retest.
Using the same credential and the same validation endpoints, I attempted to reproduce the original behavior.
The API now returned:
Invalid credentials
The key could no longer:
authenticate against Deepgram
process transcription requests
enumerate project metadata
consume paid service resources
I marked the retest as successful and confirmed that the reported credential was no longer usable.
The program awarded an additional $150 retest reward and closed the report as Resolved.
What Actually Failed
The root problem was treating a mobile application as a trusted environment.
APK files are distributed to end users.
Anything permanently stored inside them should be considered recoverable.
That includes:
API keys
client secrets
private endpoints
signing material
service-account credentials
administrative tokens
The application effectively used this model:
Android client
↓
Shared production API key embedded in APK
↓
Third-party transcription service
The client held a credential with enough access to use production resources directly.
There was no trusted backend between the mobile application and the third-party service.
A safer design would be:
Android client
↓
Authenticated request to company backend
↓
Backend validates user and intended operation
↓
Backend calls transcription provider
Another option would be to issue short-lived, narrowly scoped credentials from a trusted backend.
The important properties would be:
limited lifetime
limited scope
user or session binding
rate limits
server-side usage monitoring
the ability to revoke one client without affecting every user
A permanent account-level key should not be shipped to every installation of a mobile application.
Why Obfuscation Would Not Fix It
Moving the key to another class or obfuscating its name would not solve the vulnerability.
An attacker could still recover it through:
string extraction
decompilation
runtime hooks
network interception
memory inspection
tracing authorization headers
Obfuscation may slow down casual inspection, but it cannot make a client-side secret truly secret.
If the application must possess a reusable credential to operate, a sufficiently motivated user can obtain it.
The security boundary needs to exist on a trusted server, not inside the APK.
Demonstrated Impact
The report demonstrated that an attacker could:
Download the publicly distributed Android APK.
Decompile it without authentication.
Extract a live production Deepgram API key.
Retrieve account-related token metadata.
Enumerate internal project metadata.
Submit arbitrary audio to the paid medical transcription model.
Generate unauthorized usage billed to the affected company.
Force emergency credential revocation through sufficient abuse.
Degrade transcription quality for legitimate mobile users.
I did not claim access to patient recordings, existing transcripts, or stored medical data because that was not demonstrated.
The proven issue was unauthorized access to production transcription capacity and associated project metadata.
Hunter Takeaways
Validate the Secret, Not Just the String
A hardcoded value named API_KEY is a lead, not a complete report.
Check whether it is:
active
expired
restricted
tied to production
able to access billable features
able to expose internal metadata
The successful transcription request transformed this from a static-analysis observation into a demonstrated security issue.
Use Minimal, Controlled Proofs
There was no need to submit real speech or sensitive audio.
A two-second synthetic WAV file was enough to prove that the paid transcription endpoint could be used.
A good proof of concept should demonstrate the impact while creating as little cost and risk as possible.
Check the Public Build
When a program supplies a special APK, compare it with the current public version where the rules permit it.
The program build may be:
outdated
sanitized
configured differently
missing production-only integrations
In this case, the vulnerable credential was absent from the older HackerOne APK but present in the newer public-distribution build.
Version comparison saved the report from being closed as non-reproducible.
Explain Why a Third-Party Key Matters
Reports involving exposed third-party credentials are often dismissed when they only say:
The key is hardcoded.
The stronger questions are:
What can the key access?
Can it create billable usage?
Can it read internal metadata?
Can it modify configuration?
What happens when it is revoked?
Does the production application depend on it?
The program’s High severity decision was driven not only by financial abuse, but also by the degraded service that would result from emergency revocation.
Do Not Overstate Medical Impact
The key provided access to a medical transcription model.
That did not automatically mean patient data was exposed.
The evidence showed that an attacker could submit their own audio for processing.
It did not show access to historical recordings or existing customer transcripts.
Keeping that distinction clear made the report more accurate and defensible.
Retest the Credential Directly
The fix was credential revocation.
The most direct retest was therefore to repeat the original API calls with the exposed key.
Once each endpoint returned Invalid credentials, the original abuse path was no longer available.
Final Thoughts
The finding began with a single line inside an Android application:
public static final String DEEPGRAM_API_KEY = "[REDACTED]";
That line provided access to a live production service.
The full chain was:
Public Android APK
↓
Hardcoded production key
↓
Successful token authentication
↓
Internal project metadata
↓
Unauthorized medical transcription usage
↓
Financial and availability impact
The most important lesson is simple:
A production API key embedded in a mobile application is not a secret. It is a credential distributed to every person who downloads the APK.
Static analysis found the key.
Controlled API testing proved that it mattered.





