---
title: "State of the Keybase.io website"
author: Yarmo Mackenbach
slug: keybase-website
date: "2020-07-03 15:23:38"
published: true
discussion:
  - https://lobste.rs/s/ntfedi/state_keybase_io_website
  - https://tild.es/qa7
  - https://news.ycombinator.com/item?id=23723906
---

## Disclaimer

Two days ago, I launched [Keyoxide.org](https://keyoxide.org) which provides a few similar functions as [Keybase.io](https://keybase.io) but in an Open Source package. I've been wanting to write this post for a while but felt it could be perceived as disingenuous if posted before making my own project public. Therefore, I post this now.

## TLDR

The Keybase.io website uses non-optimized resources resulting in a slow pageload and 5+ year old versions of libraries with known and public security vulnerabilities.

## The Keybase.io website

I have opinions about the Keybase service, but this post is not about that. This is about the facts behind their website, [Keybase.io](https://keybase.io) and more specifically their [encrypt](https://keybase.io/encrypt) page, the one you use to **encrypt private and confidential messages**.

When you load that specific page, make sure to load it in a private session or window to eliminate cached resources. What do you notice?

It is slow. Really slow. I noticed so too and decided to run a [Webpagetest (link to result)](https://www.webpagetest.org/result/200627_0Q_044080ef3ab8a678721658c90d2f4706/). Out of three runs, we analyze only the median run (so not the best one, not the worst one).

![Keybase encrypt Webpagetest overview](/content/img/keybase_encrypt__wpt_overview.png)  
*keybase.io/encrypt*

## The content loaded

It takes **6.25&nbsp;seconds** to fully load the **2.9&nbsp;megabytes** that are used on this page. That is hefty for a page that is essentially a single form. I mean, look at it:

![Keybase encrypt page](/content/img/keybase_encrypt.png)  
*Why 2.9 megabytes?*

That's a regular web form. What could possibly be **2.9&nbsp;megabytes**? The javascript?

![Webpagetest run 1 overview](/content/img/keybase_encrypt__wpt_1.png)  
*How many requests? How many bytes?*

Most requests are fonts. That makes sense. Earlier, we saw the page only makes **12&nbsp;requests**, so I could imagine a few of those being several fonts files. Fortunately, fonts are only **6.5%** of the bytes loaded, so we'll forgive them.

**90&nbsp;percent** of the bytes are due to javascript and images‽ That's **2.6&nbsp;megabytes** for a form! What images?

## Javascript and image(s)

Let's grab the [waterfall](https://www.webpagetest.org/result/200627_0Q_044080ef3ab8a678721658c90d2f4706/1/details/#waterfall_view_step1) and see what is going on:

![Webpagetest run 1 waterfall](/content/img/keybase_encrypt__wpt_1_waterfall.png)  
*Run 1 waterfall*

At two points in time, the loading of the website stalls. The first stall is **2.6&nbsp;seconds** for the file `sitewide-js.js`. The second stall is **2.5&nbsp;seconds** for the file `footprints_transp.png`. Let's go.

## sitewide-js.js

This file is **4.7&nbsp;megabytes** raw and **1.2&nbsp;megabytes** gzipped. Let us look at a random excerpt:

![Javascript excerpt](/content/img/keybase_encrypt__js_excerpt.png)  
*Javascript excerpt*

This is not really optimized for performance: one could choose to minimize the javascript. Allow me to use `@node-minify/cli`.

`JS_Parse_Error [SyntaxError]: Unexpected token: name «syms», expected: punc «;»`

Hmm&hellip; Let's remove that one line which simply initializes a variable (only fix I could find). I can no longer guarantee it works but let's assume it does.

Old version: **4.7&nbsp;megabytes** raw and **1.2&nbsp;megabytes** gzipped.  
New version: **2.5&nbsp;megabytes** raw and **0.7&nbsp;megabytes** gzipped.

First win!

Well, I need to specify one thing: the website loads a gzipped version of the original file at a size of **1.23&nbsp;megabytes**. When I `gzip` it on my local machine, the original file even becomes **1&nbsp;megabytes**. I don't know what causes this discrepancy, but while we were able to reduce the raw files by 2.2 megabytes, the reduction could only become 0.3 megabytes once gzipped (on my machine&#8482;).

## footprints_transp.png

Have you found the image yet? It's the little image at the bottom of the dog (?) following footprints. Cute :)

![Footprints image](/content/img/keybase_encrypt__img.png)  
*Footprints image*

Dimensions on page: **330&nbsp;x&nbsp;90 pixels**  
Dimensions of file: **2836&nbsp;x&nbsp;770 pixels**  

That's only **8.6 times** larger than it needs to be. The bigger crime is the size: **1.4&nbsp;megabytes**. Which is 50% of the website. You guessed it. This could be better.

Using [imagecompressor.com](https://imagecompressor.com/), I can compress this full-sized image down to **398&nbsp;kilobytes** (reduction of **71%**). And I'm even allowing the full 256 colors. And the dimensions are still **8.6&nbsp;times** larger than they need to be.

Optimizing the compression and the image dimensions could yield even better results. I'm not going to bother. The devs didn't either.

Still, second win!

## Anything else we can learn?

The source code contains this:

```
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                              K E Y   B A S E

                            crypto for everyone

                        because no one we know ever
                      seems to have a public key. :-(

     No Google Analytics or other 3rd party hosted script tags on Keybase.

     And this has the added bonus that we'll never be able to serve ad code.

                                    \o/  \o/
                                  keybase team

  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

I like it when devs get creative. The third paragraph is a bit alienating, but that's my opinion.

Anything else? Given that this is all cryptography related, maybe some security related issues?

## Security

![Webpagetest security score](/content/img/keybase_encrypt__security.png)  
*Webpagetest security score*

I've ran quite a few webpagetests on different website, but a **0** security score is new to me. What does that even mean?

Well, [it turns out](https://snyk.io/test/website-scanner/?test=200627_0Q_044080ef3ab8a678721658c90d2f4706) that the entire website is built using the following libraries:

- jquery v1.11.3 (from [april 2015](https://blog.jquery.com/2015/04/28/jquery-1-11-3-and-2-1-4-released-ios-fail-safe-edition/))
- bootstrap v3.3.5 (from [june 2015](https://blog.getbootstrap.com/2015/06/15/bootstrap-3-3-5-released/))
- moment v2.7.0 (from [june 2014](https://github.com/moment/moment/releases/tag/2.7.0))

Besides the obvious aging, these libraries account for a total of six known and public security vulnerabilities, including [cross-site scripting](https://snyk.io/vuln/SNYK-JS-BOOTSTRAP-72890), [prototype pollution](https://snyk.io/vuln/SNYK-JS-JQUERY-174006) and [regular expression denial of service](https://snyk.io/vuln/npm:moment:20161019). All six security vulnerabilities have remediations.

Let the [bootstrap v3.3.5 announcement](https://blog.getbootstrap.com/2015/06/15/bootstrap-3-3-5-released/) be a painful reminder: this is *pushing&nbsp;it*.

## Wrapping up

This should give a nice overview of what could go wrong with a non-optimized and aging website. This could happen to any website. But this is Keybase, the company that promises **"secure messaging and file-sharing"**. The same company that got [$10.8 million in a Serie A funding](https://www.crunchbase.com/organization/keybase). The same company that [won't allow us to see their server code](https://github.com/keybase/client/issues/24105).

To paint a full and fair picture, there has been an [audit of the Keybase protocol [PDF]](https://keybase.io/docs-assets/blog/NCC_Group_Keybase_KB2018_Public_Report_2019-02-27_v1.3.pdf) which states that:

> [...] there were weaknesses in the Keybase implementation; these were quickly fixed.

The audit didn't include the website. I'll just end with another quote from the same audit:

> Another common theme was the presence of legacy code. [...]  
> This does not necessarily imply that legacy code is insecure, but complexity and security are intertwined – every new piece of code may contain a security vulnerability, and more code correlates with more risk.
