tls everything

Yesterday the W3C Technical Architecture Group published a new finding titled, “The Web and Encryption.” In it, they conclude:

“. . . the Web platform should be designed to actively prefer secure origins — typically, by encouraging use of HTTPS URLs instead of HTTP ones. Furthermore, the end-to-end nature of TLS encryption must not be compromised on the Web, in order to preserve this trust.”

To many HTTPS Everywhere users like myself, this seemed a decade or so beyond self-evident. So I was surprised to see a flurry of objections appear on the public mailing list thread discussing the TAG findings.

It seems bizarre to me that security-minded web developers are spending so much effort hardening the web platform by designing and implementing standards like CSP Level 2, WebCrypto, HTTP Public Key Pinning, and Subresource Integrity, while others are still debating whether requiring the bare minimum security guarantee on the web is a good thing. While some sites are preventing any javascript from running on their page unless it’s been whitelisted, other sites can’t even promise that any user will ever visit a page that hasn’t been tampered with.


small consolation: the second one has more downloads

Obviously we shouldn’t ignore arguments for a plaintext-permissive web; they’re statistically useful as indicators of misconceptions about HTTPS and sometimes also as indicators of real friction that website operators face. What can we learn?

Here’s some of my observations and responses to common anti-HTTPS points (as someone who lurks on standards mailing lists and often pokes website operators to deploy HTTPS, both professionally and recreationally):

  1.  “HTTPS is expensive and hard to set up.” This is objectively getting better. Cloudflare offers automatic free SSL to their CDN customers, and SSLMate lets you get a cert for $10 using the command line. In the near future, the LetsEncrypt cert authority will offer free certificates, deployed and managed using a nifty new protocol called ACME that makes the entire process take <30 seconds.
  2. “There is no value in using HTTPS for data that is, by nature, public (such as news articles).” This misses the point that aggregated browsing patterns, even for only public sites, can reveal a lot of private information about a person. If it weren’t, advertisers wouldn’t use third-party tracking beacons. QED.
  3. “TLS is slow.” Chris Palmer thought you would ask this and gave an excellent presentation explaining why not. tl;dr: TLS is usually not noticeably slower, but if it is, chances are that you can optimize away the difference (warning: the previous link is highly well-written and may cause you to become convinced that TLS is not slow).
  4. “HTTPS breaks feature X.” This is something I’m intimately familar with, since most bug reports in HTTPS Everywhere (which I used to maintain) were caused by the extension switching a site to HTTPS and suddenly breaking some feature. Mixed content blocking was the biggest culprit, but there were also cases where CORS stopped working because the header whitelisted the HTTP site but not the HTTPS one. (I also expected some “features” to break because HTTPS sites don’t leak referer to HTTP ones, but surprisingly this never happened.) Luckily if you’re using HTTPS Everywhere in Chrome, there is a panel in the developer console that helps you detect and fix mixed content on websites (shown below). Setting the CSP report-only header to report non-HTTPS subresources is similarly useful but doesn’t tell you which resources can be rewritten.https-switch
  5. “HTTPS gives users a false sense of security.” This comes up surprisingly often from various angles. Some people frame this as, “The CA system isn’t trustworthy and is breakable by every government,” while others say, “Even with HTTPS, you leak DNS lookups and valuable metadata,” and others say, “But many site certificates are managed by the CDN, not the site the user thinks they’re visiting securely.” The baseline counterargument to all of these is that encryption, even encryption that is theoretically breakable by some people, is better than no encryption, which doesn’t need to be broken by anyone. CA trustworthiness in particular is getting better with the implementation of certificate transparency and key pinning in browsers; let’s hope that we solve DNSSEC someday too. Also, regardless of whether HTTPS gives people a false sense of security, HTTP almost certainly gives the average person a false sense of security; otherwise, why would anyone submit their Quora password in plaintext?quora

In summary, it’s very encouraging to see the TAG expressing support for a ubiquitous transit encryption on the web (someday), but from the resulting discussion, it’s clear that developers still need to be convinced that HTTPS is efficient, reliable, affordable, and worthwhile. I think the TAG has a clear path forward here: separate the overgrown anti-HTTPS mythology from the actual measurable obstacles to HTTPS deployment, and encourage standards that fix real problems that developers and implementers have when transitioning to HTTPS. ACME, HPKP, Certificate Transparency, and especially requiring minimum security standards for powerful new web platform features are good examples of work that motivates website operators to turn on HTTPS by lowering the cost and/or raising the benefits.

certificate transparency for PGP?

Yesterday, Prof. Matthew Green wrote a nice blog post about why PGP must die. Ignoring the UX design problem for now, his four main points were: (1) the keys themselves are too unwieldy, (2) key management is hard, (3) the protocol lacks forward secrecy, and (4) the crypto is archaic/non-sane by default.

Happily, (1) and (4) can be solved straightforwardly using more modern crypto primitives like Curve25519 and throwing away superfluous PGP key metadata that comes from options that are ignored 99.999999% of the time. Of course, we would then break backwards compatibility with PGP, so we might as well invent a protocol that has forward/future secrecy built-in via something like Trevor Perrin’s axolotl ratchet. Yay.

That still leaves (2) – the problem of how to determine which public key should be associated with an endpoint (email address, IM account, phone number, etc.). Some ways that people have tried to solve this in existing encrypted messaging schemes include:

  1. A central authority tells Alice, “This is Bob’s public key”, and Alice just goes ahead and starts using that key. iMessage does this, with Apple acting as the authority AFAICT. Key continuity may be enforced via pinning.
  2. Alice and Bob verify each others’ key fingerprints via an out-of-band “secure” channel – scanning QR codes when they meet in person, reading fingerprints to each other on the phone, romantically comparing short authentication strings, and so forth. This is used optionally in OTR and ZRTP to establish authenticated conversations.
  3. Alice tries to use a web of trust to obtain a certification chain to Bob’s key. Either she’s verified Bob’s key directly via #2 or there is some other trust path from her key to Bob’s, perhaps because they’ve both attended some “parties” where people don’t have fun at all. This is what people are supposed to do with PGP.
  4. Alice finds Bob’s key fingerprint on some public record that she trusts to be directly controlled by Bob, such as his Twitter profile, DNS entry for a domain that he owns, or a gist on his Github account. This is what does. (I only added this one after @gertvdijk pointed it out on Twitter, so thanks Gert.)

IMO, if we’re trying to improve email security for as many people as possible, the best solution minimizes the extent to which the authenticity of a conversation depends on user actions. Key management should be invisible to the average user, but it should still be auditable by paranoid folks. (Not just Paranoid! folks, haha.)

Out of the 3 options above, the only one in which users have to do zero work in order to have an authenticated conversation is #1. The downside is that Apple could do a targeted MITM attack on Alice’s conversation with Bob by handing her a key that Apple/NSA/etc. controls, and Alice would never know. (Then again, even if Alice verified Bob’s key out-of-band, Apple could still accomplish the same thing by pushing a malicious software update to Alice.)

Clearly, if we’re using a central authority to certify people’s keys, we need a way for anyone to check that the authority is not misbehaving and issuing fake keys for people. Luckily there is a scheme that is designed to do exactly this but for TLS certificates – Certificate Transparency.

How does Certificate Transparency work? The end result is that a client that enforces Certificate Transparency (CT) recognizes a certificate as valid if (1) the certificate has been signed by a recognized authority (which already happens in TLS) and (2) the certificate has been verifiably published in a public log. The latter can be accomplished through efficient mathematical proofs because the log is structured as a Merkle tree.

How would CT work for email? Say that I run a small mail service,, whose users would like to send encrypted emails to each other. In order to provide an environment for crypto operations that is more sandboxed and auditable than a regular webpage, I provide a YanMail browser extension. This extension includes (1) a PGP or post-PGP-asymmetric-encryption library, (2) a hardcoded signing key that belongs to me, and (3) a library that implements a Certificate Transparency auditor.

Now say that wants to email Bob has already registered his public key with, perhaps by submitting it when he first made his account. Alice types in Bob’s address, and the YanMail server sends her (1) a public key that supposedly belongs to Bob, signed by the YanMail signing key, and (2) a CT log proof that Bob’s key is in the public CT log. Alice’s CT client verifies the log proof; if it passes, then Alice trusts Bob’s key to be authentic. (Real CT is more complicated than this, but I think I got the essential parts here.)

Now, if YanMail tries to deliver an NSA-controlled encryption key for Bob, Bob can at least theoretically check the CT log and know that he’s being attacked. Otherwise, if the fake key isn’t in the log, no other YanMail user would trust it. This is an incremental improvement over the iMessage key management situation: key certification trust is still centralized, but at least it’s auditable.

What if Alice and Bob want to send encrypted email to non-YanMail users? Perhaps the browser extension also hard-codes the signing keys for these mail providers, which are used to certify their users’ encryption keys. Or perhaps the mail providers’ signing keys are inserted into DNS with DANE+DNSSEC. Or perhaps the client just trusts any valid CA-certified signing key for the mail provider.

For now, with the release of Google End-to-End and Yahoo’s announcement to start supporting PGP as a first-class feature in Yahoo mail, CT for (post)-PGP seems promising as a way for users of these two large webmail services to send authenticated messages without having to deal with the pains of web-of-trust key management. Building better monitoring/auditing systems can be done incrementally once we get people to actually *use* end-to-end encryption.

Large caveat: CT doesn’t provide a solution for key revocation as I understand it – instead, in the TLS case, it still relies on CRL/OCSP. So if Bob’s PGP/post-PGP key is stolen by an attacker who colludes with the YanMail server, they can get Alice to send MITM-able messages to Bob encrypted with his stolen key unless there is some reliable revocation mechanism. Ex: Bob communicates out-of-band to Alice that his old key is revoked, and she adds the revoked key to a list of keys that her client never accepts.

PS: It would be strange for me to write this post without also mentioning that I will soon be joining Yahoo as the first member of a new privacy engineering team under the Paranoids, focusing on usable end-to-end encryption for Yahoo mail. I don’t start til Sept. 2 (assuming background checks pass and papers are in order), so this post represents my own views and not Yahoo’s. :)

found my new job title on a t-shirt in manila

my new job title, spotted on a shirt in a Filipino market

PPS: I figured I should save time and answer some FAQ’s about how end-to-end encryption can possibly be something-resembling-secure in a messy webmail environment, hypothetically speaking.

  1. Q: How to handle XSS and website cross-origin vulns? A: Fork Google’s end-to-end so we live in the relative safety of browser extension land.
  2. Q: Where do private keys get stored? A: I would show users a simple dialog that says, “Do you want us to backup your encryption key?” (default “no”) – if so, upload their private key encrypted with a strong passphrase that only they know. If not, warn them that their encrypted email may be gone forever if they lose their hard drive.
  3. Q: Can’t you push arbitrary malicious updates to the browser extension, thereby getting any plaintext? A: In theory, but browser extensions are just ZIP files and therefore can be packaged deterministically from a tag in a git repo to make this attack easier to detect.

Written on 8/14/14 from a hotel room in Manila, Philippines


Update (8/15/14):

Thanks for the responses so far via Twitter and otherwise. Unsurprisingly, I’m not the first to come up with this idea. Here are some reading materials related to CT for e2e communication:

Update (8/29/14):

Since I posted this, folks from Google presented a similar but more detailed proposal for E2E. There has been a nice discussion about it on the Modern Crypto list, in addition to the one in the comments section of the proposal.



4 years ago, I went to HOPE for the first time on a last-minute press pass from my college newspaper. Some relevant facts about the trip:

  • I was 19 and had never been to a hacker con before.
  • I didn’t identify as a hacker (or an activist).
  • I was too shy to talk to anyone the entire time. Combined with the fact that I knew only a few people there, I was mostly off by myself.
  • HOPE that year was the pinnacle of paranoia in probably the most paranoid period of my life. This was 2010, a few months after Chelsea Manning was arrested for leaking a trove of documents to WikiLeaks. Coincidentally, Chelsea Manning had visited my house in the autumn of 2009; this was cause enough for suspicion from certain groups and frequent questions from reporters once the WikiLeaks story broke. Julian Assange was scheduled to give the keynote at HOPE, so you can imagine the atmosphere that year.
  • Overall it was a fun experience regardless.

This year I finally made it back to HOPE. Things were a little different than last time:

  • I flew in from Europe instead of driving from Boston.
  • I was representing EFF and Freedom of the Press Foundation, two organizations that were almost-universally loved by the attendees.
  • I co-presented two talks in front of overflowing rooms of people and got lots of audience feedback.
  • I didn’t have time to talk to all the people that I wanted to, much less all the people who were trying to ask me questions.
  • Whereas last time I made it to several talks per day, this year I was working from 4 AM in the morning until whenever-I-had-to-give-a-presentation for the first 2/3rds of the conference, then running off to meetings or working shifts at the EFF/FPF booths. As a result, I made it to a total of 3 or 4 talks that weren’t mine. :(
  • It was eerie to have contributed to a project that kept getting name-dropped during the conference by the likes of Daniel Ellsberg and Barton Gellman. Literally dozens of people approached me to say that they wanted to help out with SecureDrop or set up an instance. Wow!

Predictably, it was strange to be a very-minor celebrity at a conference where I’d previously felt like an outsider and deliberately tried to make myself invisible. 4 years ago, my experience in the last 4 days would have seemed impossible for a plethora of reasons: I wasn’t a good public speaker*, I had a lot of self-doubt that I could contribute anything to the event,  I felt weird for not having the same interests and background as the vast majority of people at HOPE, I didn’t know much about computers, I didn’t think that I was working on anything interesting, etc.

*Public speaking workshops are immensely helpful here; so does taking an introductory voice acting class.

Despite the slowly-fading jetlag and piling exhaustion after a month of international travel, it felt nice to contribute back to a conference that had been an eye-opening experience to me the first time.

Many thanks to the following people for working on presentations with me, giving last-minute feedback, and/or letting me sleep in their room: Parker Higgins, Bill Budington, Garrett Robinson, Trevor Timm, Runa Sandvik, James Dolan, Kevin Gallagher, Noah Swartz. Also thanks for Oliver Day for appointing me CSO of his company even though I haven’t fixed the SSL cert for his website yet.

Photo by Scott J. O’Brien (@scottjobrien)

Software Transparency: Part 1

Say that you want to “securely” acquire an app called EncryptedYo for “securely” communicating with your friends. You go to the developer’s web site, which is HTTPS-only, and download a binary executable. Done!

Perhaps if you’re paranoid, you fetch the developer’s GPG key, make sure that there’s a valid trust path to it from your own key, verify the detached signature that they’ve posted for the binary, and check that the checksum in the signature is the same as that of the binary that you’ve downloaded before installing it.

This is good enough as long as the only things you’re worried about are MITM attacks on your network connection and compromise of the server hosting the software. It’s not good enough if you’re worried about any of the following:

  • The developer getting a secret NSA order to insert a backdoor into the software.
  • The developer intentionally making false claims about the security of the software.
  • The developer’s build machine getting compromised with malware that injects backdoors during the packaging process (pre-signing) or even a malicious compiler.

All of the above are *Very Real Worries* (TM) that users should have when installing software. As a maintainer of a security-enhancing browser extension used by millions of people, I used to worry about the third one before HTTPS Everywhere had a deterministic build process (more on that below). If my personal laptop was compromised by a malicious version of zip that rewrote the static update-fetching URL in the HTTPS Everywhere source code before compressing and packaging it, literally millions of Firefox installations would be pwned within a few days if I didn’t somehow detect the attack before signing the package (which is basically impossible to do in general).

You might instinctively think that the scenarios above are at least *detectable* if the software is open source and has been well-audited, but that’s not really true. Ex:

  1. How do I know that some binary executable that I downloaded from actually corresponds to the well-audited, peer-reviewed source code posted at
  2. How do I know that the binary executable that I downloaded is the same as the one that everyone else downloaded? In other words, how can I be sure that it’s not my copy and *only* my copy that has a secret NSA backdoor?

So it looks like there’s a problem because we usually install software from opaque binaries or compressed archives that have no guarantee of actually corresponding to the published, version-controlled source code. You might try to solve this by cloning the EncryptedYo repo and building it yourself. You can even fetch it over Tor and/or compare your local git HEAD to someone else’s copy’s if you want a stronger guarantee against a targeted backdoor.

Unfortunately that’s too much to ask the average person to do *every single time* they need to update the software, especially if EncryptedYo’s target audience includes non-technical people (ex: Glenn Greenwald).

This is why post-Snowden software developers need to start working on new code packaging and installation mechanisms that preserve “software transparency,” a phrase perhaps first used in this context by Seth Schoen. Software transparency, unlike open source by itself, is a guarantee that the packages you’re installing or updating were created by building the published source code.

(Side note: Software transparency has open source code as a prerequisite, but a similar concept that I’ve been calling “binary transparency” can be applied to closed-source software as well. Binary transparency is a guarantee that the binary you’re downloading is the same as the one that everyone else is downloading, but not that the binary is non-compromised. One way to get this is to compare the checksum of your downloaded binary gainst an out-of-band append-only cryptographically-verifiable log (phew) of binary checksums, similar to what Ben Laurie proposed in this blog post.)

In the last year, software transparency has finally started to become a front-and-center goal of some projects. Organizations like Mozilla and EFF are beginning to work on fully-reproducible build processes so that other people can independently build their software packages from source and make sure that their checksums are the same as the ones posted on or Mike Perry of the Tor Project has written about the painstaking, years-long process that it took to compile the Tor Browser Bundle deterministically inside a VM, but for many other software projects, the path to a reproducible build is as simple as normalizing timestamps in zip.

Of course, a reproducible build proccess doesn’t by itself impact the average user, who is unlikely to try to replicate the build process for Firefox for Android before installing it on their phone. But at least it means that if Mozilla started posting backdoored binaries because their build machine was compromised, some members of their open source development community could in theory detect the attack after-the-fact and raise suspicions. That’s more than we could do before.

IMO, every reasonably-paranoid software developer should be trying to adopt an independently reproducible build process. Gitian is a good place to start.

(Part 2 of this series, which I haven’t written yet, is probably going to be about implementing software transparency in a way that protects end users before they get pwned, which nobody is doing much of yet AFAIK. In particular, it would be nice to start discussing ways to enforce software transparency for resources loaded in a browser, in hopes that this will bring either some clarity or more shouting to the debate about whether in-browser crypto apps are a good idea.)

stuff i use

This was my favorite part of my interview with The Setup:

What would be your dream setup?

Let’s start with the easy ones. I would like (1) an e-book reader that has the portability and battery life of a Kindle, runs free software out-of-the-box, and doesn’t support DRM; (2) an open-source maps application for Android/CyanogenMod that can provide biking and public transit directions for any city that I happen to be in; and (3) a usable open-source password manager that syncs to mobile devices, integrates with browsers, and meets some set of minimum security requirements. (I’ll work on the latter if someone else does the first two.)

Slightly more ambitious: every device should come with root access for the user if they want it. Going down the stack, it would be nice if all computing devices by default ran a free BIOS and other free firmware on top of easily-modifiable, open hardware.

Respecting the autonomy of users by allowing them to understand and modify their devices is crucial for creating widespread technical literacy and, subsequently, a world in which ordinary people can detect when their rights are being threatened by technology providers and governments. I have a crazy dream that, someday, ordinary families will sit down at their kitchen tables to install software updates together and read the change logs aloud over breakfast.

Shooting for the stars now: let’s design computers so that software engineering doesn’t force us to occupy constrained, mostly-immobile positions in florescent-lit rooms for 8+ hours every day. I’d like to code and go backpacking at the same time.

a boring xss dissection

Hi there. Have a funny picture:


Today, I was briefly worried by the observation that mainstream media takes 24-36 hours to start freaking out about over half of web encryption being fundamentally broken, compared to 2-3 hours for an XSS bug in a Twitter client that causes self-retweeting tweets and unexpected rickrolls and such. Then I remembered that most Americans watch TV for like 4+ hours per day. (XSS is arguably the most telegenic class of software QA issues.)

I don’t use TweetDeck, but I managed to download the much-XSSed Chrome extension today shortly before it was fixed. I unminified the content script (the one that modifies page content on the client side, therefore probably causing whatever XSS was there) and took a diff with the patched version (3.7.2) after it came out. Pastebin here.

A couple things stood out:

  1. Some people on Twitter (or maybe the people who XSSed their accounts, haha) implied that the XSS was due to Twitter not escaping user input. This seems false, because I can see safely-escaped HTML in HTTP responses from Twitter in my browser. This is sort of interesting, because it implies that the TweetDeck client is somehow unescaping escaped HTML.
  2. The bulk of the not-very-well-obfuscated-but-still-hard-to-read diff between 3.7.1 and 3.7.2 was ripping out emoji “parsing” code. “parsing” is in quotes because TweetDeck processes tweets and tries to replace all Emoji characters with HTML image tags before showing them to you.

3.7.2, quite happily, replaced the “emojify” function with the identity function (pictured above).

After staring at the diff some more, I sort-of figured out what was going on. TweetDeck runs a utility function on the DOM that extracts every text node, t, that contains an emoji character. Then for each text node t, it does the equivalent of:

someDiv.innerHTML = this.emoji.parse(t.nodeValue);
var i = document.createDocumentFragment();
while (someDiv.hasChildNodes()) {
t.parentNode.replaceChild(i, t);

where emoji.parse is the function that replaces emoji with HTML img tags.

“innerHTML is evil!!” one might say. This is true, but not the sole problem in this case because Chrome and Firefox will not automatically execute js inside <script> tags created by setting innerHTML. While it’s true that you can get scripts to execute anyway through <img onError=”…”> or whatever, there were consistent reports today of people who got XSSed through <script> tags in tweets.

So given that it’s not 120% obvious where the bug is in the TweetDeck code, here’s what happens when you try out the code snippet above on a tweet containing both XSS payload and emoji, like this one:


For convenience, I ID’ed the element containing the tweet text with “xss-test”. Looks like the innerHTML is properly escaped to start with!


Now let’s grab the text node corresponding to the tweet, create a new div, and set the innerHTML of the div to be the nodeValue of our text node (TweetDeck would have converted emoji into images at this point, but this was already done to start with). Note that the new innerHTML doesn’t seem to have safe HTML entity-encoded characters (&lt;, &gt;) anymore!


Moving on, we create a documentFragment and append *both* children of the new div to it. Note that the second child is a script element, which wasn’t originally part of the DOM! Finally, we do some DOM surgery to replace the original text node with our newly-created fragment.


And voila, the <script>…</script> text in the tweet disappears, because now the browser sees it as a script element instead of as text.

It’s not hard to imagine ways this bug could have been created. UX designer says, “We need to add better emoji rendering before the release next week.” Another developer decides that emoji need to be converted into images and copies-and-modifies some code from the same script that renders “@” mentions in text as HTML links but forgets to re-sanitize the non-emoji text. The code looks pretty okay, with no obvious problems, so it gets pushed out.

This is the sort of thing that I suspect is *all over* every semi-clever agilely-developed app, waiting to be uncovered as soon as a mischievious Austrian teenager accidentally hits the wrong key. Most applications simply don’t have enough users for these bugs to surface yet, and many will die out before they ever do, which is a blessing in itself. Sometimes the bugs are found and fixed before they explode all over Ars Technica, either by a scrutinous engineer or by an honest user or perhaps by someone looking to claim a bug bounty.

But these generally aren’t bugs that can be trivially prevented, unless the developer who’s working on improving emoji rendering for your project also happens to have enough of a security background to know that changing some safe innerHTML to the nodeValue of the safe innerHTML will suddenly create dangerous innerHTML. Or perhaps if you had a dedicated person reviewing each commit for security holes as it comes in, or at least a pre-release hook for automated fuzz testing to check for unwanted script execution, but last I checked, nobody was telling web application devs to do this.

My favorite solution is actually for everyone to just deal with being XSSed semi-frequently in the future. This means that developers should stop exposing sensitive tokens to javascript (or quickly expire tokens that are), use safe CSP directives whenever possible, and make it easy for users to review and undo actions. On the other side of the bargain, users should either start using NoScript-like browser settings to whitelist Javascript or at least blacklist known Rickroll links.

don’t forget to secure cookies ppl

Update (5/28/14): Regrettably, most of the stories covering this blog post have been all “OMG EVERYTHING IS BROKEN” rather than “Here’s how to make things better til WordPress rolls out a fix” (which I humbly believe will take a while to *fully* fix, given that their SSL support is so patchy). So, given that most people reading this are probably coming from one of those articles, I think it’s important to start with the actionable items that people can do to mitigate cookie-hijacking attacks on WordPress:

  1. If you’re a developer running your own WordPress install, make sure you set up SSL on all relevant servers and configure WordPress to auth flag cookies as “secure.”
  2. If you’re a WordPress user, don’t be logged into WordPress on an untrusted network, or use a VPN. If you are and you visit a site (which confusingly may not actually have a domain name), your auth cookies are exposed.
  3. [Experimental, probably not recommended] You can manually set the “secure” flag on the WP auth cookies in your browser. There’s no guarantee that this works consistently, since the server can always send a set-cookie that reverts it into an insecure cookie. It may cause some WP functionality to break.
  4. If you suspect that your WP cookie may have been stolen in the past, you can invalidate it by (1) waiting 3 years for it to expire on the server or (2) resetting your password. Note that logging out of WordPress does *not* invalidate the cookie on the server, so someone who stole it can use it even after you’ve logged out. I verified that resetting your WP password does invalidate the old cookie; there may be other ways, but I haven’t found any.

Original post below.


While hunting down a bug report for Privacy Badger, I noticed the “wordpress_logged_in” cookie being sent over clear HTTP to a WordPress authentication endpoint ( on someone’s blog.



Sounds like bad news! As mom always said, you should set the “secure” flag on sensitive cookies so that they’re never sent in plaintext.

To check whether this cookie did anything interesting, I logged out of my wordpress account, copied the wordpress_logged_in cookie into a fresh browser profile, and visited in the new browser profile. Yep, I was logged in!

This wouldn’t be so bad if the wordpress_logged_in cookie were invalidated when the original user logged out or logged back in, but it definitely still worked. Does it expire? In 3 years. (Not sure when it gets invalidated on the server side, haven’t waited long enough to know.)

Is this as bad as sending username/password in plaintext? I tried to see if I could reset the original user’s password.


That didn’t work, so I’m assuming WordPress uses the actually-secure cookie (wordpress_sec) for super important operations like password change. Nice job, but . . .

It turns out I could post to the original user’s blog (and create new blog sites on their behalf):


I could see private posts:


I could post comments on other blogs as them:


I could see their blog stats:


And so forth. I couldn’t do some blog administrator tasks that required logging in again with the username/password, but still, not bad for a single cookie.

Moral of the story: don’t visit a WordPress site while logged into your account on an untrusted local network.

Update: Thanks to Andrew Nacin of WordPress for informing me that auth cookies will be invalidated after a session ends in the next WordPress release and that SSL support on WordPress will be improving!

Update (5/26/14): I subsequently found that the insecure cookie could be used to set someone’s 2fac auth device if they hadn’t set it, thereby locking them out of their account. If someone has set up 2fac already, the attacker can still bypass login auth by cookie stealing – the 2fac auth cookie is also sent over plaintext.

Update (5/26/14): A couple people have asked about whether the disclosure timeline below is reasonable, and my response is here.

Disclosure timeline:

Wed, 21 May 2014 16:12:17 PST: Reported issue to, per the instructions at; at this point, the report was mostly out of courtesy, since I figured it had to be obvious to them and many WP users already that the login cookie wasn’t secured (it’s just a simple config setting in WordPress to turn on the secure cookie flag, as I understand it). Received no indication that the email was received.

22 May 2014 16:43: Mentioned the lack of cookie securing publicly.

22 May 2014 17:39: Received response from Andrew Nacin (not regarding lack of cookie securing but rather that the auth cookie lifetime will soon be that of a regular session cookie).

23 May 2014 ~13:00: Discovered two-factor auth issue on accident, reported to both and in reply to original email. I also mentioned it to Dan Goodin since I found the bug while trying to answer a question he had about cookies, but I did not disclose publicly.

25 May 2014 15:20: Received email response from saying that they were looking into it internally (no mention of timeline). Wrote back to say thanks.

26 May 2014, ~10:00: Ars Technica article about this gets published, which mentioned the 2-fac auth issue. I updated this blog post to reflect that.

26-27 May 2014: Some commenters on the Ars Technica article discover an arguably worse bug than the one that the original article was about: WordPress sends the login form over HTTP. (Even though the form POST is over HTTPS, the local network attacker can modify the target on the HTTP page however he/she wants and then it’s game over.) This wouldn’t be so bad if everyone used a password manager and changed passwords semi-regularly, since most people are likely to login to WordPress through their blog’s admin portal (which is always HTTPS as far as I can tell), except that password reuse is rampant. Robert Graham subsequently published this blog post.

29 May 2014, 5:52: Received reply from WordPress saying they would email me again when fixed.

30 May 2014, 14:51: Andrew Nacin says all issues are supposedly fixed.

How to make a less-leaky Heartbleed bandage

Mashable just put out a nice-looking chart showing “Passwords You Need to Change Right Now” change in light of the recent Heartbleed carnage. However, it has some serious caveats that I wanted to mention:

  1. It’s probably better to be suspicious of companies whose statements are in present-tense (ex: “We have multiple protections” or even “We were not using OpenSSL”). The vulnerability existed since 2011, so even if a service was protected at the time of its disclosure 3 days ago, it could be have been affected at some point long before then. I am also skeptical that every single company on the list successfully made sure that nothing that they’ve used or given sensitive user data to had a vulnerable version of OpenSSL in the last 2 years.
  2. The article neglects to mention that password reuse means you might have to change passwords on several services for every one that was leaked. The same goes for the fact that one can trigger password resets on multiple services by authenticating a single email account.
  3. You should also clear all stored cookies just in case the server hasn’t invalidated them as they should; many sites use persistent CSRF tokens so logging out doesn’t automatically invalidate them. (Heartbleed trivially exposed user cookies.)
  4. Don’t forget to also change API keys if a service hasn’t force-rotated those already.
  5. It remains highly unclear whether any SSL certificates were compromised because of Heartbleed. If so, changing your password isn’t going to help against a MITM who has the SSL private key unless the website has revoked its SSL certificate and you’ve somehow gotten the revocation statement (LOL). This is complicated. Probably best not to worry about it right now because there’s not much you can do, but we all might have to worry about it a whole lot more depending on which way the pendulum swings in the next few days.
  6. Related-to-#5-but-much-easier: clear TLS session resumption data. I think this usually happens automatically when you restart the browser.

Nonetheless, Mashable made a pretty good chart for keeping track of what information companies have made public regarding the Heartbleed fallout.

Zero-bit vulnerabilities?

The other day, I overheard Seth Schoen ask the question, “What is the smallest change you can make to a piece of software to create a serious vulnerability?” We agreed that one bit is generally sufficient; for instance, in x86 assembly, the operations JL and JLE (corresponding to “jump if less than” and “jump if less than or equal to”) are represented by:

JL  → 0F 8C (00001111 10001100)
JLE → 0F 8E (00001111 10001110)

and the difference between the two could very easily cause serious problems via memory corruption or otherwise. As a simple human-understandable example, imagine replacing “<” with “<=” in a bus ticket machine that says: “if ticket_issue_date < today, reject rider; else allow rider.”

At this point, I started feeling one-bit-upsmanship and wondered whether there was such a thing as a zero-bit vulnerability. Obviously, a binary that is “safe” on one machine can be malicious on a different machine (ex: if the second machine has been infected with malware), so let’s require that the software must be non-vulnerable and vulnerable on two machines that start in identical states. For simplicity, let’s also require that both machines are perfectly (read: unrealistically) airgapped, in the sense that there’s no way for them to change state based on input from other computers.

This seems pretty much impossible to me unless we consider vulnerabilities probabilistically generated by environmental noise during code execution. Two examples for illustration:

  1. A program that behaves in an unsafe way if the character “A” is output by a random character generator that uses true hardware randomness (ex: quantum tunneling rates in a semiconductor).
  2. A program that behaves in an unsafe way when there are single-bit flips due to radioactive decay, cosmic ray collisions, background radiation, or other particle interactions in the machine’s hardware. It turns out that these are well-known and have, in some historical cases, caused actual problems. In 2000, Sun reportedly received complaints from 60 clients about an error caused by background radiation that flipped, on average, one bit per processor per year! (In other words, Sun suffers due to sun.)

Which brings up a fun hypothetical question: if you design an SSL library that will always report invalid certificates as valid if ANY one bit in the library is flipped (but behaves correctly in the absence of single-bit flip errors), have you made a zero-bit backdoor?