Upcoming Advisory for Apache Tomcat Vulnerability – CVE-2019-0221

We will be releasing an advisory on a security vulnerability that was reported to the Apache Software Foundation, specifically in Apache Tomcat. This issue is being tracked under CVE-2019-0221. The issue was discovered by Nightwatch Cybersecurity Research and reported to Apache via the EU FOSSA-2 project, hosted by Intrigri.

UPDATE: Advisory has been posted here.

Related links:

  • Apache advisory – here
  • CVE entry – here
  • Tomcat security pages – v7, v8 and v9

Finding Unlisted Public Bounty and Vulnerability Disclosure Programs with Google Dorks


Bug bounty/vulnerability disclosure platforms are used by companies to coordinate the reporting, triaging and in some case, rewarding,  of security vulnerabilities. In many platforms the various programs are not always public – some may be public, some maybe unlisted but public, some may be private and some may be invite-only. In this post we outline how we found a set of public programs that were not listed on the platform site but were findable via Google searches.

Embedded Forms

While most platforms host the program information, policies and submission pages on their own sites, their customers may occasionally want to embed or host a particular program on the site owned by the customer or one that is agnostic, not the platform. For these uses cases, some platforms have an embedding feature which allows customers to embed a submission form for vulnerabilities within the customer owned website or host it via a website that doesn’t appear to be connected to the platform vendor. Here is documentation for some of the platforms:

The problem is that if a company ends up embedding a form, it will get indexed by Google and can be found via a Google search. The trick is to look for something unique in the text of the form. Here is for example a vulnerability reporting form for Walmart, provided by BugCrowd – as you can see it says “Powered by BugCrowd”

Screen Shot 2019-05-02 at 7.40.02 PM

If you check the BugCrowd public list of programs, WalMart will not be listed:

Screen Shot 2019-05-02 at 9.10.49 PM

However, it may appear on the list such as the one from Disclose.IO:

Screen Shot 2019-05-04 at 11.48.15 PM.png

Google Dorking Other BugCrowd Embedded Forms

Now if you put the text from the form into Google as follows, you can find a bunch of other ones as well:

"powered by bugcrowd" -site:bugcrowd.com

These do not appear in the BugCrowd public list, and many of them are not in the Disclose.IO list. Example:

Screen Shot 2019-05-02 at 9.08.36 PM

What About HackerOne?

For HackerOne, a blog post shows an example of a form which looks very similar to a standard one.

Screen Shot 2019-05-02 at 9.19.01 PM

We tried Googling for the following query got no results:

"powered by hackerone" "submit vulnerability report"

Eventually, we just Google for the following and got many unrelated results:

"submit vulnerability report"

Among those, we were able to find a single embedded form from HackerOne for a non-public program. Because HackerOne uses an image for their “Powered By” message, it is probably harder to find or maybe not that many programs use the HackerOne forms yet 🙂 [Based on some additional feedback it looks like HackerOne forms are generated dynamically and may not be indexable by Google, see Lyft as an example]

Screen Shot 2019-05-02 at 9.21.34 PM

Screen Shot 2019-05-02 at 9.23.10 PM

Screen Shot 2019-05-02 at 9.24.50 PM

What About Synack?

While Synack doesn’t operate any public programs, they do offer a managed disclosure process which is hosted by “responsibledisclosure.com”. A simple Google Search against that site shows a bunch of programs (these are listed in Disclose.io):


Screen Shot 2019-05-02 at 9.34.33 PM.png

Other Platforms?

We haven’t explored other platforms but feel free to do so yourself 🙂

Responses from the Platforms

This issue was reported to the three platforms listed above, here are their responses:


“We don’t guarantee that all public programs are listed directly on Bugcrowd.com – a number of companies leverage our Embedded Submission Form to host a Bugcrowd submission form (like you’re finding via these searches) directly on their own sites. Even though these programs aren’t directly advertised on our Programs page, they’re not meant to be considered private/secret. It’s up to the companies choosing to use this form to decide how and where they display it.

Nothing is being “leaked,” as any companies who do choose to run private programs that include an intake via our Embedded Submission Form understand what they’re doing: The Embedded Submission Form integration enables you to host a submission form from your own website rather than through Bugcrowd. This integration provides a streamlined workflow so that researchers can easily submit vulnerability reports directly to you, while allowing you to continue to manage and track submissions through Crowdcontrol.

You can manage and track submissions through Crowdcontrol for private and public programs. These are companies choosing to host our ESF on public/indexed pages, so the fact that they’re not listed at https://bugcrowd.com/programs is exactly what you’d expect.”


“This feature is not intended to be private but to help ease programs’ engagement with the larger hacker community. We do caution programs, prior to setting up the feature, to understand that their program will no longer be private if the form is exposed in a public way. Beyond that, the program benefits from our normal private experience, and we do not include other call outs or invitations to the programs on HackerOne unless explicitly requested.

Some companies, like Punchh, use this feature to allow researchers to submit reports to their vulnerability disclosure program via their own website.”


“Although we do not advertise our Responsible Disclosure programs, they are publicly accessible and not considered to be private information”


2019-02-20: Reported to Synack and rejected
2019-02-22: Reported to BugCrowd and rejected
2019-05-02: Draft blog post shared with HackerOne, Synack and BugCrowd
2019-05-03: Comments received from platform vendors
2019-05-04: Blog post published

Remote Code Execution (RCE) in CGI Servlet – Apache Tomcat on Windows – CVE-2019-0232


Apache Tomcat has a vulnerability in the CGI Servlet which can be exploited to achieve remote code execution (RCE). This is only exploitable when running on Windows in a non-default configuration in conjunction with batch files.

The vendor released a fix in Tomcat versions 7.0.94, 8.5.40 and 9.0.19. Users are encouraged to upgrade as soon as possible. CVE-2019-0232 has been assigned to track this issue.

Vulnerability Details

Common Gateway Interface (CGI) is a standard protocol to allow web servers to execute command line programs / scripts via web requests. This protocol also allows passing of command line arguments to the script or program being executed via URL parameters. The protocol itself is defined in RFC 3875.

The following CGI request:

  • http://localhost:8080/cgi/test.bat?&dir

converts to:

  • test.bat &dir

Apache Tomcat supports execution of CGI scripts / programs in a non-default configuration via a special CGI servlet. This servlet also parses URL parameters and translates them into command line arguments. The actual execution of the CGI scripts happens via Java Runtime Environment (JRE)’s java.lang.Runtime class, exec() function.

When CGI support is enabled in Apache Tomcat in Windows, and command line argument passing is enabled, it is possible to cause command injection via parameter interpolation when calling a batch file (*.bat / *.cmd). This happens because “cmd.exe” performs interpolation on some special characters before execution which can cause other shell commands to be called. Neither Apache Tomcat or the Windows JRE perform any kind of input validation for these special characters. A partial list of these characters can be found here and here. Additional information about why this issue is specific to the Windows JRE can be found in this blog post by Markus Wulftange.

Steps To Replicate

1. Install a Java Runtime Environment (JRE) in Windows.

2. Download a vulnerable version of Tomcat and extract.

3. Modify the conf\context.xml file on line 19, to enable privileged context:

<Context privileged="true">

4. Modify conf\web.xml to enable the CGI Servlet by removing the comments around line 387 as follows and adding the following parameters (enableCmdLineArguments is only needed for Tomcat 9):


5. Enable the CGI servlet by removing comments around this – you also need to change the URL pattern to match the one in the previous step (“cgi”):


6. Create a folder for the CGI files:

mkdir webapps\ROOT\WEB-INF\cgi

7. Place the following text into a batch file located in “webapps\ROOT\WEB-INF\cgi\test.bat”

@echo off
echo Content-Type: text/plain
echo Hello, World!

8. Run Tomcat via the following command:

cd bin
catalina run

9. Trigger the following URLs and observe the dir command being run:



Additional Notes – Environment Variables and Path

By default, Tomcat doesn’t pass all of the environment variables from the parent process that runs Tomcat itself. That means that if you run “set”, you will not see any environment variables other than those set by Tomcat itself. This also means that you would need to spell out the directory path of the command you are trying to run. However, if the “passShellEnvironment” parameter is set to true, the variables from the parent process will be passed through and you can call any command in PATH as well as view those variables. If the command cannot be found, there will be a error in the console log “XXXX is not recognized as an internal or external command”.

Example of trying to run a command without a full directory including the Tomcat console logs:

s5 s6

Examples of running with the parameter being set or spelling out the directory path:


Example of trying to view the environment variables without and with the passShellEnvironment parameter being set to “true”:



Additional Notes – Memory Leaks / Denial of Service

If the command being executed is a long running command, it maybe possible to cause a denial of service or a memory leak. This happens because Tomcat waits for the OS process to complete.

Here is an example of netstat being triggered:



Additional Notes – Other Commands and STDERR

The “executable” parameter indicates which executable should be used to run the script. By default, this is set to “perl” with the expectation that the files being executed are Perl scripts. If this is set to empty, then it is possible to execute batch files since those are executed by “cmd.exe”. HOWEVER, it seems that the command interpolation only happens with batch files – if this is set to real program, then command interpolation doesn’t necessary occur and this vulnerability may be not exploitable.

Also, if the command being triggered outputs to STDERR instead of STDOUT, that output doesn’t get piped back to the web request – instead it goes to the Tomcat console log.

Here is an example when “java.exe” is set as the executable parameter and produces output to STDERR:


Vendor Response

This issue was responsibly reported to the vendor via the EU FOSSA bounty program operated by Intigriti. Vendor analysis indicated that the core cause for this issue has to do with the way the Java Runtime Environment (JRE) interprets command arguments in Windows specifically and doesn’t impact Apache Tomcat when used with other operating systems. The vendor assigned CVE-2019-0232 to track this issue and provided a fix.

The vendor fix consists of two parts:

  • Disabling command line arguments from being passed to the CGI servlet in the default configuration (“enableCmdLineArguments” set to “false“) for Tomcat 7 and 8  – this was already disabled by default in Tomcat 9.
  • Adding a new configuration parameter (“cmdLineArgumentsDecoded“) to the default CGI configuration that will be used for input validation if passing of command line arguments is enabled and will be set to the following regular expression (OS specific). Note that if the user changes this parameter, they may become vulnerable again.
    • Windows - [[a-zA-Z0-9\Q-_.\\/:\E]+]
    • Other operating systems - [.*]

Affected Versions and Mitigation

Apache Tomcat is only vulnerable to this issue if the following conditions are met:

  • Running on Windows
  • CGI support is enabled either via the web.xml for a specific web application or the server as whole (see documentation). This is disabled by default.
  • The “privileged” setting is set to “true” in the Context element. This is “false” by default.
  • Tomcat 9 onlyenableCmdLineArguments is set to “true” (enabled by default in Tomcat 7 and 8)
  • The “executable” parameter is empty, and the the CGI scripts being executed are batch files (either .bat or .cmd). It is not clear if other commands that use “cmd.exe” are vulnerable as well.

The vendor indicated that the following versions are vulnerable (no information is available on earlier versions):

  • Tomcat 9 – versions 9.0.0.M1 through 9.0.17 (9.0.18 is not affected)
  • Tomcat 8 – versions 8.5.0 to 8.5.39
  • Tomcat 7 – versions 7.0.0 to 7.0.93

Users are encouraged to upgrade to the following fixed versions or later:

IMPORTANT NOTE: even when running a fixed version, you SHOULD NOT change the “cmdLineArgumentsDecoded” configuration parameter to a different value. If you do, your installation may become vulnerable. If an upgrade is not possible, users can apply one of the following mitigations:

  • Disable CGI support (it is disabled by default)
  • Or set the “enableCmdLineArguments” parameter to “false“. This setting will disable command line arguments from being passed via the CGI servlet.

Bounty Information

This report satisfied the requirement of the EU FOSSA bounty program and a bounty has been paid.


Blog post on JRE behavior: see here (Markus Wulftange)
CGI Standard: RFC 3875
CVE-ID: CVE-2019-0232
CVSS v2.0 Score: 9.3 – (AV:N/AC:M/Au:N/C:C/I:C/A:C)
CVSS v3.0 Score: 8.1 – (AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H)
Tomcat CGI Servlet source code: see GitHub
Vendor advisory: see here


Text of the advisory written by Yakov Shafranovich.


2019-02-14: Initial report submitted to the platform
2019-02-17: Initial report validated by the platform
2019-03-03: Report acknowledged by the vendor
2019-03-14: Interim evaluation received from the vendor
2019-03-22: Communication with the vendor
2019-04-10: Public advisory issued by the vendor
2019-04-30: Public disclosure by reporter

Upcoming Advisory for Apache Tomcat Vulnerability – CVE-2019-0232

We will be releasing an advisory on a security vulnerability that was reported to the Apache Software Foundation, specifically in Apache Tomcat. This issue is being tracked under CVE-2019-0232. The issue was discovered by Nightwatch Cybersecurity Research and reported to Apache via the EU FOSSA-2 project, hosted by Intrigri.

UPDATE: The advisory has been published here.

Related links:

  • Apache advisory – here
  • CVE entry – here

Third Party Android App Storing Facebook Data Insecurely (Facebook Data Abuse Program)


A third-party Android application with Facebook API access was found to be copying user data into storage outside of Facebook, and storing it insecurely in two separate locations. This issue was reported to Facebook via their Data Abuse Bounty program and the insecure storage locations have been secured on November 12th, 2018. The Facebook app associated with this application has been removed from the Facebook platform but the Android application remains available in Google’s Play Store. The number of affected users is unknown. [ADDED: 02/15/2019 – Google has been notified].


In April 2018, FaceBook announced a new Data Abuse Bounty program that rewards “people with first-hand knowledge and proof of cases where a Facebook platform app collects and transfers people’s data to another party to be sold, stolen or used for scams or political influence“.

In September 2018, we found an Android application in the Google Play store that purports to provide additional functionality to Facebook users that is not available through the platform. At the time of writing, the application had more than 1,000,000 downloads. After downloading the application, and examining it using JADX, we found that the application was using Facebook APIs to access data for the logged in user and copying to several storage locations outside of Facebook. Upon further examination, it was clear that at least two of such locations (a Firebase database and an API server) were making this data available without any authentication and without HTTPS. This would allow an attacker to mass download the user data accumulated by the application from its users.

We do not know for sure how many users have been impacted or exposed, but one of the databases accessed contained over 1,000,000 records. [ADDED: 02/15/2019 – The application purported to provide additional statistical information about the logged-in user’s Facebook account. There is a privacy policy within the application but it is ambiguous about the transfer of data].

Issue #1 – Storing user data in an public Firebase database

During our examination of the application, we located a Firebase database that the application was communicating with. The database was configured in test mode, which allowed anonymous public access by visiting the URL of “https://DATABASE.firebaseio.com/.json“. As seen in the attached screenshot, the database contained data obtained from Facebook. Aside from confirming the initial permission issue, we did not access or explore this database any further.



Issue #2 – Storing user data in a non-SSL server without authentication

During our examination of application, it become clear that the server that the application was communicating with, did not use SSL and was being accessed without authentication. As seen below, this would allow an attacker to download the data collected by the application from Facebook via a regular browser as well as spy on any connections between the application and the server. Aside from confirming the initial permission issue, we did not access or explore this database any further.



Vendor Response and Mitigation

We contacted the Facebook Data Abuse Bounty program but did not contact the vendor directly. After Facebook completed its review, the two insecure locations have been secured on November 12th, 2018. The Facebook app associated with this application has been removed from the Facebook platform but the Android application remains available in Google’s Play Store. [ADDED: 02/15/2019 – Google has been notified].

This discovery qualified under the terms of the Facebook Data Abuse Bounty Program and a bounty payment has been received.


Facebook report # 10101718616795015
Google reference # 8-7487000025062


This advisory was written by Yakov Shafranovich.


2018-09-17: Initial report submitted to Facebook, initial response received
2018-11-12: Issued fixed
2018-11-27: Bounty decision received; sent disclosure request
2018-11-30: Facebook asked for additional time before disclosure
2019-01-15: Investigation has been finalized, FaceBook asked for a copy of the disclosure
2019-02-03: Draft disclosure shared for review
2019-02-14: Public Disclosure
2019-02-15: Minor updates; notification sent to Google

Content Injection in Amazon Kindle’s FireOS [CVE-2019-7399]


The FireOS operating system provided by Amazon for Fire tablet devices can be injected with malicious content by an MITM attacker. An attacker can also capture the serial number of the device. The root cause is lack of HTTPS for legal content (terms of use and privacy policy) within the settings section.

The issue was discovered in FireOS v5.3.6.3 and fixed by the vendor in v5.3.6.4 that was released in November 2018. Devices will automatically update to the latest version. CVE-2019-7399 has been assigned by MITRE to track this issue.

Vulnerability Details

FireOS is an operating system provided by Amazon for the Fire tablet devices.  It is a customized fork of Android. While monitoring network traffic on a test device, we observed that several calls from the settings section (terms of use and privacy policy) are done without HTTPS and can be injected with malicious content by an MITM attacker. It is also possible for the attacker to observe this traffic and capture the serial number (DSN) of the device.

Screenshots of the captured traffic:

Screenshot_2018-09-03-13-11-20 Screenshot_2018-09-03-13-11-26

Steps To Replicate (on Ubuntu 18.04)

1. Install the application on the Android device but do not start it.

2. Install dnsmasq and NGINX on the Linux host:

sudo apt-get install dnsmasq nginx

3. Modify the /etc/hosts file to add the following entry to map the domain name to the Linux host:

192.168.1.x www.kindle.com
192.168.1.x kindle.com

4. Configure /etc/dnsmasq.conf file to listen on the IP and restart DNSMASQ

sudo /etc/init.d/dnsmasq restart

5. Add a file with malicious content (you may need to use sudo):

cd /var/www/html
mkdir support
echo powned >support/privacy
echo powned >support/terms

6. Modify the settings on the Kindle device to static, set DNS to point to “192.168.1.x”. AT THIS POINT – the Kindle device will resolve DNS against the Linux computer and serve the large servers file

7. Tap “Settings”, “Legal and Compliance”, and tap either “Terms of Use” or “Privacy”. Observe injected content.

Vendor Response and Mitigation

The issue was discovered in FireOS v5.3.6.3 and fixed by the vendor in v5.3.6.4 that was released in November 2018. Devices will automatically update to the latest version. MITRE assigned CVE-2019-7399 to track this issue.


Amazon tracking # PO135449968
CVE-ID: CVE-2019-7399


Text of the advisory written by Yakov Shafranovich.


2018-09-03: Initial report to the vendor
2018-09-04: Report triaged and being reviewed by the vendor
2018-09-17: Communication from the vendor, issue still being reviewed
2019-01-10: Fix confirmed, communication regarding disclosure
2019-01-30: Vendor pinged about CVE assignment
2019-02-03: Draft advisory sent for review
2019-02-04: CVE issued by MITRE
2019-02-07: Public disclosure; minor syntax updates

Thoughts on the MSI/JAR Authenticode Bypass

Earlier today, Google’s VirusTotal published a blog post about a new way to bypass code signing in Windows via JAR files:

Microsoft Windows keeps the Authenticode signature valid after appending any content to the end of Windows Installer (.MSI) files signed by any software developer. This behaviour can be exploited by attackers to bypass some security solutions that rely on Microsoft Windows code signing to decide if files are trusted. The scenario is especially dangerous when the appended code is a malicious JAR because the resulting file has a valid signature according to Microsoft Windows and the malware can be directly executed by Java.

In short, an attacker can append a malicious JAR to a MSI file signed by a trusted software developer (like Microsoft Corporation, Google Inc. or any other well-known developer), and the resulting file can be renamed with the .jar extension and will have a valid signature according Microsoft Windows. For example, via the command “copy /b signed.msi + malicious.jar signed_malicious.jar”. The victim can be infected with just a double-click in such a file.

Here are some quick thoughts from our research team – note that we were not involved in this effort and have no insider knowledge. This is entirely based on public sources.

How can ZIP and EXE files be combined?

First of all, how is it possible that the same exact file can be executable both by Windows and Java? The trick lies in how Windows executable files work – as described in Microsoft’s documentation. Basically, the OS reads the file from the beginning, looking at the magic value of “MZ” followed by headers, then followed by the file content. We are going to assume that there is a table in the file that tells the reader how long each segment is, and therefore it is possible to append arbitrary data to the end of the file without it breaking.

A JAR file, however, is essentially a ZIP file. ZIP files have their index or central directory in the end of the file, and it is possible to prepend data in the beginning of the file and that file still being valid. That means that you can combine a Windows executable that is read from the beginning and rely on its headers and tables to tell the reader where to stop, and do the same for the ZIP content in the end of the file. Both files remain valid, while combined together. Also, while the example provided by VirusTotal is a JAR file, the same trick would work for other ZIP-based formats like Microsoft Office (DOCX/XSLX/etc), OpenOffice (ODT/ODS/etc), etc. Of course, this assumes that the software reading these files goes to the central directory of the ZIP and doesn’t check the magic value in the beginning.

Here is an modified example of PE files from Wikipedia, and a ZIP file example from OASIS, showing the direction in which file content is read:

revengpefile                  zip

Combined together:



What is Microsoft Code Signing / Authenticode?

As per the original blog post and other technical documentation from Microsoft, the code signing in question is Authenticode which is used by Microsoft for Windows executables, drivers, and other files. The purpose it to make sure the file originated from a trusted publisher. There is also a command line tool included in Windows called “SignTool” which is used for signing and verifying files.

The way code signing works is described in a Microsoft technical document here. It is essentially a digital signature using PCKS7 and special X.509 certificates (code signing certificates issued by CAs). It is connected to the same PKI infrastructure as SSL certificates with some additional checks by CAs when issuing the certificate (not at sign time). Like all other digital signatures, it is essentially some sort of a hash signed by a private key of the holder of the certificate which is then verified by the public key in the X.509 certificate. The certificate itself is verified against public PKI infrastructure just like SSL.

Example appears below (from Microsoft documentation):screen shot 2019-01-16 at 8.00.15 pm

Bypassing Code Signing

In a standard digital signature scenario such as PGP or S/MIME, the entire content of the message is hashed to produce a message digest using a function like SHA. That hash is then digitally signed using the sender’s private key. Note that the entire message is hashed – this allowing the receiver to check if it was modified or not, not just bits and pieces.

One of the common refrains in security is “never roll your own crypto”, which in this case includes choosing what to hash. In the case of Authenticate, it appears that the file hash does not cover the entire file. As described in this document, information in the end of the file (after the second “remaining content” above) ARE NOT included in the hash (emphasis added):

Information past of the end of the last section. The area past the last section (defined by highest offset) is not hashed. This area commonly contains debug information. Debug information can generally be considered advisory to debuggers; it does not affect the actual integrity of the executable program. It is quite literally possible to remove debug information from an image after a product has been delivered and not affect the functionality of the program. In fact, this is sometimes done as a disk-saving measure. It is worth noting that debug information contained within the specified sections of the PE Image cannot be removed without invaliding the Authenticode signature.


This means that it is trivial to simply append another file like a JAR to the end of another digitally signed file, then rename it a JAR and have the resulting file look valid in Windows since the digital signature check will stop before reading the content of the JAR file. At the same time, the file will be executable by Java since it will read from the end ignoring any of the signed content appearing in the beginning. The same would apply for other ZIP based formats like Microsoft Word and this may allow an attacker to send a malicious document while masquerading it as a legit one. Additionally it appears from the blog post that some A/V and security products use the Authenticode signature as a shortcut to validate files so they don’t need to scan them.

Another possible use of this technique is to make attribution murky since some analysts may take the Authenticode signature at face value and not realize that the malware inside may not be from the publisher that signed the file.

An additional idea would be to use this trick to exfiltrate data out of an organization by putting the extra data in the end of the file. This assumes that the DLP and similar tools monitoring outbound traffic rely on the Authenticode signature as well.

Microsoft’s code signing method isn’t the only one that exists. Similar methods exists for Java, Adobe AIR, Android, MacOS, Debian, etc. Further research is needed to see if similar issues exist in other code signing schemes.

(Written by Yakov Shafranovich)

Chrome Browser for Android Reveals Sensitive Hardware Information (partial fix available)

[NOTE: This is an expanded version of an earlier post from 2015 with updated information and fix from the vendor]


Google’s Chrome browser, WebView and Chrome Tabs for Android discloses information about the hardware model, firmware version and security patch level of the device on which it is running.  This also affects any Android applications that are using Chrome to render web content.

This information can be used for track users and fingerprint devices. It can also be used to determine which vulnerabilities a particular device is vulnerable to in order to target exploits.

While the vendor (Google) rejected the initial bug report in 2015, they had issued a partial fix in October 2018 for Chrome v70. The fix hides the firmware information while retaining the hardware model identifier. All prior versions are believed to be affected. Users are encouraged to upgrade to version 70 or later. Since this fix doesn’t apply to WebView usage, app developers should manually override the User Agent configuration in their apps.

Both the vendor and MITRE refused to issue a CVE number to track this issue since they do not consider it to be security related.

Background — Chrome and Headers

The Chrome browser for Android is provided by Google as the default browser in the Android operating system for mobile devices. It is based on the Chromium open source project. It also provides the WebView and Custom Tabs APIs for other applications running on the Android platform, to be used for rendering web content within the apps themselves without opening a separate browser window.

As all browsers, Chrome sends a variety of headers as part of every request to the web servers it communicates with. These headers are defined in the HTTP protocol, latest standard of which can be found in RFCs 7230, 7231, 7232, 7233, 7234 and 7235. Among these is the User-Agent header which is the subject of this post.

The “User-Agent” header in HTTP is defined by RFC 7231, section 5.5.3 as follows:

The “User-Agent” header field contains information about the user agent originating the request, which is often used by servers to help identify the scope of reported interoperability problems, to work around or tailor responses to avoid particular user agent limitations, and for analytics regarding browser or operating system use.

Background — Android Model and Build ID

Android devices have a build-in MODEL and BUILD ID, identifying the phone model and Android build. They are defined in in android.os.Build.MODEL and android.os.Build.ID properties. These are further defined in the Android Compatibility Definition document (section 3.2.2) as follows:

MODEL — A value chosen by the device implementer containing the name of the device as known to the end user. This SHOULD be the same name under which the device is marketed and sold to end users. There are no requirements on the specific form

ID — An identifier chosen by the device implementer to refer to a specific release, in human-readable format. This field can be the same as android.os.Build.VERSION.INCREMENTAL, but SHOULD be a value sufficiently meaningful for end users to distinguish between software builds. The value of this field MUST be encodable as 7-bit ASCII and match the regular expression “^[a-zA-Z0–9._-]+$”.

An attempt to map models to more descriptive names can be found on GitHub. A list of known build IDs for Nexus devices can be found here and here. Software build information easily maps to the security patch levels for many devices as seen on this Google page (based on date).

Vulnerability Details

As per Chrome docs, the Chrome for Android User Agent string includes the Android version number and build tag information. This information by default is also sent when applications use Android’s WebView and Chrome Custom Tabs APIs to serve web content in their own applications. While Android does offer ability to override these (via WebSettings.setUserAgent() in WebView), most applications choose not to do that to assure compatibility by relying on the default header.

Aggravating this issue is that the user agent header is sent always, with both HTTP and HTTPS requests, often by processes running in background. Also, unlike the desktop Chrome, on Android no extensions or overrides are possible to change the header other than the “Request Desktop Site” option on the browser itself for the current session.

For example of a user-agent header for Chrome Beta, on Nexus 6, with Android v5.1.1:

Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.34 Mobile Safari/537.36

When a user chooses the “Request Desktop Site” option, the user agent header sent is a generic Linux header instead. Here is an example for Chrome Beta, on Nexus 6, with Android v5.1.1:

Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.34 Safari/537.36

The difference is that on mobile mode, the following string is extra:

Android 5.1.1; Nexus 6 Build/LYZ28K

The fact that it identifies the operating system and its version is not unique. This follows generally what many other browsers have been doing on desktop and mobile. It is the build tag that is the problem. As described above, the build tag identifies both the device name and its firmware build. For many devices, this can be used to identify not only the device itself, but also the carrier on which it is running and from that the country. It can also be used to determine which security patch level is on the device and which vulnerabilities the device is vulnerable to.

An example can be easily seen from the above where build LYZ28K can be easily identified as Nexus 6 running on T-Mobile, implying a US presence. It would also be trivial to use the build information to figure out the carrier based on which carriers are known to be at what build number. Build numbers are easily obtainable from manufacturer and phone carrier websites such as this one.

Replication Instructions

To replicate this issue or to check if your device is affected, you can visit any website that shows the user agent headers being sent by your browser such as or you can type “view user agent” in Google search. Alternatively, you can use JavaScript as follows on a site like JsFiddle:


Vendor Response and Mitigation

Bug # 494452 has been filed for this bug in 2015 against Chromium, and was rejected by the vendor as “WAI” – “Working As Intended”. However, in 2018, a new bug # 860229 was filed by the vendor along with a feature request, and this was partially fixed in October 2018 in Chrome v70 for Android by removing the firmware build information from the header. The device model number remains.

The fix only applies to the Chrome application itself, and not to the WebView implementation used by application developers as per the following explanation:

Does not apply the change to Android Web View as mandated by the Android Compatibility Definition Document.

Users are encouraged to update to Chrome v70 or later to fix this issue. Application authors should use WebSettings.setUserAgent() method to set the override the user agent. While many are reluctant to do so in order to lose compatibility, we would like to suggest the following approach of using the default user agent and erasing the build and model information in it.

Both the vendor and MITRE refused to issue a CVE number to track this issue since they do not consider it to be security related.


Chromium bugs: 494452 and 860229
Chromium feature request # 4558585463832576
Our talk about abusing this: originally given at BSides Philly 2016 – see here
Original blog post from 2015: see here


This advisory was written by Yakov Shafranovich.


2015-05-31: Initial report submitted to the vendor
2017-06-03: Bug rejected by the vendor as “WAI” – “Working As Intended”
2015-09-30: Initial public disclosure published
2016-12-06: Public talk at BSides Philly
2018-07-04: New Chromium bug filed directly by the vendor
2018-08-10: Fix merged for Chrome
2018-10-29: Fixed version released
2018-12-25: Updated disclosure published

Wickr Me for Android Allowed Screen Capture

Wickr offers a suite of applications which provide secure instant messaging, voice and audio calls. The Android version of Wickr Me Messenger allowed screenshots to be taken by other apps on the device because FLAG_SECURE option wasn’t used.

To replicate, try the following:

  1. Open the application.
  2. Press Power + Volume Down at any sensitive screen and observe a screenshot being taken.

The underlying reason is because the app is not using “FLAG_SECURE” for such screens (more information on FLAG_SECURE can be found in our earlier blog post). By contrast, many Android apps with higher security requirements use it.

Vendor Response and Mitigation

This issue was reported in May 2016 against version, and was fixed in September 2018 in version 4.55.1. A bounty has been paid.


  • Google Play Link to the app – see here
  • Our earlier blogpost about FLAG_SECURE on Android – see here