Byte 255


Poking The Bear: Is TunnelBear’s Client Safe To Use?

TunnelBear is quickly becoming one of the most popular options for “normal” people to use VPNs. It’s easy to use and the heavily targeted, yet non-obnoxious marketing doesn’t hurt either. Plus I have an irrational affection for brands that combine awesome products with a cute front-end. The same reason I’m in love with Neat microphones.

Not Open-Source

TunnelBear is cheap and non-intrusive, but not open-source. The account management happens on their servers, using unique user tokens. So the client is not all that critical, and doesn’t provide much attack surface. But attacking TB’s service is not the point of this post.

That said, the client is after all a proprietary piece of software that runs on your PC, managing the most private part of your communication: your internet connection. So it’s important to know what makes it tick, and what it knows and shares about you.

TunnelBear has yet to have a major fracas, and (spoilers), I didn’t find any in my analysis. Yet there might be certain parts of this software that may surprise you.


TunnelBear targets the broader, “average Joe” audience, so my analysis is focused on the Windows client. Saying “TunnelBear is not open-source” isn’t quite true. First of all it uses FOSS components, and it’s written in C#, which, if you’re not familiar with reverse engineering, is the same thing as having a neatly formatted and optimized copy of the full source code — minus the comments.


The TunnelBear base installation copies some 165 files onto your PC. The separate parts of the software are

  • Assets (such as audio files and pictures used in the UI)
  • Certificates (issued by Google, root and key)
  • Language assemblies (for some odd reason my copy contains the French resource, despite the actual app being English)
  • A copy of obfs4’s proxy engine (a Tor component)
  • Various (very brittle) Batch scripts to manage route-ing, monitoring and DNS (-cache)
  • A copy of the Hyper-V Network VSP Bind management tool
  • A build of OpenSSL
  • OpenVPN drivers
  • The GalaSoft MVVM Light Toolkit
  • BitStadium’s HockeyApp SDK
  • IntelliBear, a DNS proxy, which is not written in C#. This is the app that uses aforementioned Batch scripts.
  • MahApps Metro, a UI toolkit
  • ManagedWifi (NativeWifi), a simple wrapper around the wlanapi Windows API
  • NewtonSoft JSON, a JSON (de)parser
  • All other TunnelBear code as .NET assemblies (with full debug info)

So quite heavy. But that’s what you need to close every possible leak on Windows. If you just want to proxy your browser, something like TorGateway is more than enough. But not every app honors the internet options, so other connections still expose your actual IP. You need to proxy everything.


The app is launched by this hilarious script:

Set WshShell = CreateObject(“WScript.Shell”)
cmds=WshShell.RUN(“TBear.Client.exe”, 0, True)
Set WshShell = Nothing

So let’s take a look at our entry point, TBear.Client. I’m looking at version There are multiple mentions of a version 3 in the code, and many checks to enable or disable updates to v3, more on that later. This assembly is linked to all the image, sound and font assets. It also contains the default English resources.

No bear glove = risky internet love
Grr. Your privates are showing…

etc. pp.

First off is the connection helper routine. It simply waits for an internet connection by using Utils.PingTunnelBear() with a default maximum of 3 attempts. It pings as a check.

The actual app is launched async. On startup, it first restores the default proxy. This applies to the “internet options” proxy settings withing windows. These are stored in Software\Microsoft\Windows\CurrentVersion\Internet Settings as an address and a flag (on/off). It only resets the proxy address if the existing one is local, which is a good idea if you are already using another proxy.

It also makes sure to resume operation and to reconnect the VPN when the system power mode changes.

Now to the actual startup handler. This is the first time we encounter a curious flag called Utils.IsProd. This flag controls a number of things. One of them being the server that is accessed by the client, which is for production, but otherwise.

More importantly though, this disables or enables the frighteningly comprehensive logging-to-stdout that is baked into every routine:

Utils.IsGodModeUnlocked = false;
if (!Utils.IsProd) {

Another curious flag is the self-explanatory AutoUpdater.IsBeta.

It then tests of the system (or the current user) is capable of running IntelliBear (the DNS proxy, remember). This is done by creating a dummy VPN instance on port 53. If that fails, the user probably doesn’t have permission or something is already running there.

Finally we get to parse the command line options. The following are available:

  • -lang, for setting the UI language
  • -autoconnect, whether to auto connect on startup
  • -tcp, to force the VPN to use TCP
  • -intellibear-error, logs the last IB error ( -intellibear-info logs the last info statement)
  • -intellibear-verbose forces IB into verbose mode.
  • -reset forces a reset
  • -uitest mode runs this UI test mode
  • -autologin user password uses these credentials to login and stores them “safe”ly on disk

Depending on whether this is your first launch you are presented with either the “onboarding” or “main” window. Telemetry via Hockey is also initialized at this point.

But let’s take a closer look at the storage routine for our most sensitive data:

int k = Array.IndexOf<string>(e.Args, “-auto-login”);
if (e.Args.Length > k + 2) {
Utils.SafeSave(“STORE_USER”, e.Args[k + 1]);
Utils.SafeSave(“STORE_PASS”, e.Args[k + 2]);

We find this function in TBear.Common, a collection of helper functions. Of course this function has logging built in, but the only thing that’s logged are the names of the keys that are modified. Long story short, the data is encrypted using ProtectedData and saved to the IsolatedStorage KVS. No issues here. Basically all settings are managed within IsolatedStorage.

Account Settings

The fun stuff happens server-side. If you click anything that changes state in your account, you will do so on the TunnelBear website. For example, this is what happens when you click “upgrade” in the UI:

Utils.LaunchBrowser(string.Format(Utils.GetBaseWebsite() + “account#/change?token={0}”, task.Result.Result.ToString()));

The base website is either the production or staging server. But how is the token generated?

new TBearClient().GetDeepLinkToken(Utils.SafeRestore(“STORE_USER”), Utils.SafeRestore(“STORE_PASS”));

That doesn’t seem to have a terribly high amount of entropy considering the average user’s password. Let’s dig deeper.

The DeepLinkToken generator is actually a two-step process, as it consults the API first.

API Fallback

Same as with the front-end, the API’s base URL depends on whether it’s the production version. So it’s https://(staging) But hold on. This API could be blocked. So how does TunnelBear circumvent this?

This is were the API backup IP LUT comes in. It’s filled on startup by updating from AWS. The whole process is a bit convoluted (everything is done with delegated task in TunnelBear), but it boils down to this:

The API usually returns four IPs. This is a pretty awesome fallback that I wouldn’t have expected, but the implementation does have to major issues in my opinion:

  • This API (even though I censored it above) can be trivially polled by any software. It can then be added to a blocklist automatically.
  • All IPs can be blocked by either service signature or even region, as they are extremely close, both in a network and geo sense.

GetApiBase() though doesn’t use the IPs, but only the gateway, which is the first entry in the LUT.

Login Token

But I digress. Back to the login token. Nothing special, which is kind of worrying. It’s a simple POST request to api/core/getLoginToken. The POST data is

  • username=turbo
  • password=nicetry

That’s it. The header also refuses caching and uses the language from the settings. I want to view my token. Now, the fallback actually makes this way easier. I redacted the full API URL above, because the API domain has a CloudFlare WAF, so the IP probably shouldn’t be public ;-).

This also interferes with cURL (you just get a CF challenge site if you don’t fake the UA). But using one of the IPs: Success!

$ curl -data “” -k https://(redacted)/core/getLoginToken

PASS indicates success, as the server will also send a 200 OK if the request fail. The -k kills certificate errors (no domain, duh!).

Now, we can see that the token really only does depend on the cleartext password. If you know the e-mail address of someone who uses TunnelBear, you just need to brute-force the password. Of course that is completely infeasible. With the normal URL, you are going to hit CloudFlare limits, with the IPs you can distribute an attack across four points, but your are still going to be discovered as a traffic anomaly pretty quickly.

If you are presented with the website that contains the DeepLinkToken, you’ll still need to log in. But if you are logged in, it’ll take you right where it should.

Diagnose Mode

If your bear is misbehaving, there’s a troubleshooting mode, which can be launched with the command line arg -help.

AutoConnect Wifi

An unusual feature of TunnelBear are it’s WiFi management capabilities. If you think about it, this is an essential feature (and currently exclusive to the windows version). It polls the Windows WLAN API to check if the current WiFi network is open and immediately enables the VPN connection even if it was off.

If you have logging enabled, the log will contain the names of all WiFi profiles that were connected and whether they are secure or not. This part of the client doesn’t phone home, so your privacy remains intact.

Vigilant Mode

Another interesting, but essential setting is the vigilant mode. My criticism here is that (probably for UX reasons) it’s disabled by default.

It’s a fact of life, WiFi connections drop. […] Vigilant helps to protect you by blocking any unsecured traffic while TunnelBear is connecting.

So… how?

VigilantFirewall, a class living in TBear.Common, is a thin wrapper around a patchwork of external utils (like everything network-related on Windows).

To block everything, it of course needs to allow exceptions, which are just the program files TunnelBear uses. It uses the Windows firewall API to manage it’s rules. So, no voodoo magic or self-made nonsense.

Hardware Fingerprint

“Wait. You said privacy! What in the world does it want with a hardware fingerprint?!”, I hear you ask.

Every time an instance of TBearClient is created, it creates a hardware fingerprint. And spoilers again, yes, it is shared with their server. But let’s not get ahead of ourselves. First we need to dissect how this fingerprint is created in the first place. The data used is

  • BIOS metadata (manufacturer, version, ID etc.)
  • CPU (speed, name, ID)
  • The machine GUID from the registry
  • The MAC address
  • GPU ID

But actually, most of this file is dead code. I suspect it has been copy & pastes from something else. The only relevant routine is this:

That’s slightly weird though. It first tries to get the GUID from the 32bit registry. The value returned can be null, in which case it tries the 64bit registry. However, this call could fail, too, potentially setting the fingerprint to null and causing an exception elsewhere.

Anyhow, this function doesn’t call any other method present in this class. OK. Now, who uses this fingerprint?

New User Registration

That. The registration is a larger POST request to the API. The header contains the language and curiously the OpenVPN version. The POST data is:

  • User
  • Password
  • Assembly name, version and OS name
  • Country
  • A flag whether to return JSON
  • The fingerprint

So it’s pretty clear why the fingerprint is sent on registration. If you combine cURL with a small script and a junkmail API, you could create new TunnelBear accounts within seconds on the same machine, circumventing the paid model altogether. However, all of them would have the same hardware fingerprint and you’d be blocked quickly.

But, this is kind of pointless. Because now you know how to generate bogus fingerprints. The only identifying info then is your IP. But again, use something like TorGateway and simply rotate circuits between each account generation. Infinite free TunnelBear. Stuff for TunnelBear to think about, not a critical bug by any means though.


Other things are pretty routine. Setting proxy info, firing up the VPN etc. Nothing special, and nothing phones home. Certificates are created and installed JIT.


If you just download the free version of TunnelBear, IntelliBear is disabled. It allows you to configure tunneling on a per-URL basis. However, the IntelliBear runtime ships by default and isn’t secured by anything else.

In order to know about what URLs are used, you need to proxy DNS. Now, many of you are probably using a residential internet connection. Which means you are probably also using a DNS proxy without knowing it. I see a lot of people changing their DNS to e.g. Google’s. The truth is: It doesn’t matter. Whatsoever. Even if you think you are using that DNS, and your PC thinks it’s using it. Most ISP employ transparent DNS proxies, that MITM your DNS requests and serve you from a local POP to increase performance. However, these DNS caches often suffer from stupidly high cache times (that you can’t purge) and sometimes even serve ads. If you want to know if you are affected, see this discussion.

Happy to report that TunnelBear has it’s own functions to detect DNS leaks and even IPv6 leaks. Awesome!

Let’s poke the IntelliBear:

C:\Program Files\TunnelBear>intellibear32.exe -help
Usage of intellibear32.exe:
-debug=”error”: Debug level, set between error, info or verbose
-f=”domains.txt”: Domain list file path
-intel=”none”: Is using Intellibear?
-log=””: Log path
-p=””: Which proto use for lookup domain
-r=””: Regex pattern for match domain to use tcp proto
-s=”scripts”: Script directory path
-server=””: Server ip
-t=0: How many seconds to timeout
-tap=”utun0": Which Tap adapter to use

The actual wrapper code for IB is missing from the assemblies, though.

In Conclusion

After reviewing thousands of lines of code, I can pretty confidentially say that TunnelBear has no privacy issues, doesn’t collect unnecessary telemetry and is a streamlined, fast and intuitive app.

So, if you were looking at the feature set of TunnelBear and you need nothing more, I can recommend it from a privacy standpoint. If you are in desperate need of absolute* privacy, Tor will be the better choice.

All this also means that it’s pretty easy to implement your own TunnelBear client!

Coming Up

You might notice that I didn’t touch on the more advanced features in depth. That’s because V3 is out, where most of these are completely overhauled (hah, get it?). So coming up is a complementary audit of the paid V3 version. Stay tuned.

Topics of interest

More Related Stories