9 min read

Hawk Authentication bug - Firefox Accounts payload bypassing integrity validation

Hawk Authentication bug - Firefox Accounts payload bypassing integrity validation

HawkAuth protocol is widely adopted by Firefox Accounts and appears in Postman in a very short list of supported API authentication methods which indicates HawkAuth is vastly more popular than you might first expect.

HawkAuth protocol history‌‌

The origins of HawkAuth appears to be with Eren Hammer then shortly sponsored by hapijs before being completely acquired by Mozilla in "maintenance mode" and renamed to just "hawk", which we will learn here that removing the "auth" from the name serendipitously accurate, as you only get Authentication optionally by design.

Jump to the timeline if you're here for the vulnerability disclosure events.

How is the HawkAuth protocol implemented?

‌‌The protocol is an adaptation of  IETF draft where the Hawk API is describe in this document.

There are many client and server side implementations that are disparate in their interpretations of the API.

Where is HawkAuth implemented? ‌

There are several libraries that are available for projects to consume and implement Hawk Authentication:

And a growing number of contributions to the Kubernetes ecosystem are using Hawk, it's becoming so numerous there's almost no value listing them all here.

What exactly is HTTP Holder-Of-Key Authentication?‌‌

Simply put; If you have an API (server) that you want to ensure the requester (client) is whom they claim to be and the request you received (payload) is not modified from what was sent (integrity), then you can pre-share a secret with the client to 'sign' the request which proves they have the secret without them exposing it or giving it back to you and you can only get this proof if the server verifies the request using the secret and payload too.

So when you choose HawkAuth you expect that messages that are signed by the shared secret (symmetrical signatures) that both ends know, and can prove without either end disclosing the secret to the other. This is done by each end reconstructing the signature (sign the request) and comparing the signature they signed to the signature the client signed and sent to them claiming they used the expected secret. If the signatures generated at both ends match, the message being signed was not modified and we have proof the sender has the same secret.

We know the sender is who they claim to be because the request they signed has proven integrity properties ensured by the symmetric key we expected them to use when proving authenticity.

The literal definition of Authentication

Hawk does not do the server verification by default, it uses only client provided signatures, comparing the client signature matches the client signature! Therefore Hawk may never actually do any Authentication at all unless you very explicitly and far too onerously tell it too do the verification on purpose.

This is Hawk, by default, does nothing of value at all that TLS doesn't already provide

It had one job, and it only does that job if it's forced to. Otherwise it does basically nothing useful

Are there any fixes?

Apparently not, officially it's intended to be this way.‌‌ Unofficially there is a new branch for a major release version 3.0.0 that has not been made official, but the changes, documentation, change log, unit test - EVERYTHING is done and ready for 2 years! It "is patched" but that is not acknowledged by Mozilla and Hawk is internally deprecated, the whole HawkAuth should be properly (ethically) retired, but it's not widely known which a problem we will cover further on..

EDIT: Stefan Arentz (@st3fan on GitHub) a former Mobile Browser Engineer at Mozilla, has a Go implementation that does not have the flaw. Also the Rust usage within Mozilla. Both of these assemble the signature correctly, not using client provided payload hash as-is, it will compute it's own hash using the payload at time of verification for the expected signature for the HMAC comparison).

Maintainers have security domain knowledge, right?

You hope so. Or at least be open minded and willing to acknowledge input from others with domain knowledge..

I hate myself for throwing shade, but this is egregious where ignoring it would be complicit in failing to meet the one expectation of the wider community that trusted an Authentication library, so here it is.

Comparing a cryptographic hash, a HMAC no less with the word "Authentication" literally right there, where the hash token was extracted from a HTTP Header called "Authorization" and the protocol called HawkAuth has a primary design goal to cryptographicly verify signatures for the use to do secure Authentication operations!
No.. this is not security-sensitive

Makes you feel really warm and fuzzy when you see developers, not influenced by anything you have done because at the time they had no idea about your existence, when they have no domain knowledge at all about the code they are producing, or the tests they are writing that have the sole purpose of gaining a level of assurance the code is correct.

If there is no fundamental dare I say basics (AAA) security domain knowledge expressed in the code, the tests, the issues raised, or the bug bounty discussions - we have a clear systemic problem!

Our adoption and usage of HawkAuth

Before Trivial Security had a web dashboard

It was a collection of services with an Elasticsearch database that a small group of penetration testers and security engineers used for professional engagements, naively those services intercommunicated relying on HawkAuth, which was migrated to mohawk, then during the SaaS migration we identified the systematic issues and abandoned HawkAuth entirely.

Get free Trivial Security monitoring

Zero effort, zero maintenance, Threat Intelligence that alerts you only for events that are validated and require your attention, no up-sells, no ads or marketing. Justkeeping you safe on the internet.

Sign Up for a Free forever plan

How does this effect Firefox Accounts?‌‌

FXA is where Authentication is handled for Firefox Accounts, the following list are the public endpoints that are easily observable by just running Firefox and observing where the Authentication is included:

Sample of FXA endpoints - thousands (or millions) more exist beyond FXA

  • /account/create
  • /account/login
  • /account/keys
  • /account/devices
  • /account/device
  • /account/device/destroy
  • /account/device/commands
  • /account/devices/invoke_command
  • /account/devices/notify
  • /account/status
  • /account/reset
  • /account/destroy
  • /recovery_email/status
  • /recovery_email/resend_code
  • /recovery_email/verify_code
  • /recovery_email/secondary/verify_code
  • /recovery_email/secondary/resend_code
  • /session/verify_code
  • /session/resend_code
  • /certificate/sign
  • /password/change/start
  • /password/change/finish
  • /password/forgot/send_code
  • /password/forgot/resend_code
  • /password/forgot/verify_code
  • /password/forgot/status
  • /account/lock
  • /account/unlock/resend_code
  • /account/unlock/verify_code
  • /account/attached_client/destroy
  • /session/destroy
  • /session/reauth
  • /session/duplicate
  • /account/sessions
  • /account/attached_clients
  • /session/status
  • /securityEvents
  • /account/profile
  • /account
  • /sms
  • /sms/status{country}
  • /recovery_emails
  • /recovery_email
  • /recovery_email/destroy
  • /recovery_email/set_primary
  • /account/login/send_unblock_code
  • /signinCodes/consume
  • /signinCodes
  • /totp/create
  • /totp/destroy
  • /totp/exists
  • /session/verify/totp
  • /recoveryCodes
  • /session/verify/recoveryCode
  • /recoveryKey
  • /recoveryKey/{recoveryKeyId}
  • /recoveryKey/exists
  • /introspect
  • /oauth/authorization
  • /oauth/token
  • /oauth/destroy
  • /account/scoped-key-data
  • /oauth/subscriptions/clients
  • /oauth/subscriptions/plans
  • /oauth/subscriptions/active
  • /oauth/subscriptions/updatePayment
  • /oauth/subscriptions/customer
  • /oauth/subscriptions/active/{subscriptionId}
  • /oauth/subscriptions/reactivate

There is also the FXA server side that has 'patched' the risk (not what I would call the response), which is more accurately described as them changing from HawkAuth defaults (blind trust) to the payload verification (it's one job) that will do the HTTP Holder-Of-Key Authentication (which is the one and only expected function of Hawk in the first place, right?).

Finally, that FXA Payments Server specifically was at risk and Mozilla themselves said it is "a significant vulnerability".

I refuse to publish the proof-of-concept, any specifics about how an attack can work, or be specific about the flaw. I only discuss there was a vulnerability, Hawk is now completely removed from FxA but it is still widely utilised, even growing in popularity among repositories in the Kubernetes ecosystem.


  • Agreement in an ADR 0022 that FxA has deprecated HawkAuth
    May 29, 2020, 3:04 AM GMT+10
  • Issue #6 mozilla-services/hawkauthlib
    Jul 8, 2021, 4:16 PM GMT+10
    The incoming hash of the payload is being trusted and not verified
    (the library never included a server-side signature construction to compare to the presented signature, it used only the client signature for verification, which verifies itself against itself - not actually a verification at all)
  • Bugzilla 1719614
    2021-07-08 01:19 PDT
    Reported the incorrect hash validation in hawk library for Mozilla backend services and API where the hawkauthlib is utilised.
  • Issue #38 mozilla/PyHawk
    Jul 10, 2021, 3:34 PM GMT+10
    Security Vulnerability in Payload Verification
  • Pull Request #7 mozilla-services/hawkauthlib
    Jul 10, 2021, 12:02 PM GMT+10
    Fixes validation, new and existing unit tests passing, still not merged
  • Bugzilla 1719964 created
    July 10, 2021 01:52 PDT
    PoC for a MitM attack against Firefox Accounts
  • Bugzilla 1719614 Mozilla confirm the code for the both Python and new Rust sync server is not validating payload either
    July 11, 2021 17:44 PDT
  • Issue #284 mozilla/hawk
    Jul 14, 2021, 1:12 PM GMT+10
    The incoming hash of the payload is being trusted and not verified
  • CVE Request 1106124 directly to Mitre
    July 14, 2021
  • Mitre cannot issue a CVE for a vulnerability that includes an open source library which has the name of a CNA (Mozilla)
    July 15, 2021
  • Issue #9850 mozilla/fxa
    Jul 15, 2021, 2:48 AM GMT+10
    Mozilla private JIRA task to add payload veification on sensitive routes, as discussed in my bounty submission 1719614
  • Bugzilla 1719964 follow up
    August 04, 2021 20:24 PDT
  • Bugzilla 1719964 Mozilla responded with no update
    August 08, 2021 11:56 PDT
  • Pull Request #10199 mozilla/fxa
    Aug 21, 2021, 5:24 AM GMT+10 merged Aug 21, 2021, 6:43 AM GMT+10
    Adding payload validation to signature verification, an option available in the vendored (fork) of hapijs/hawk (no longer public)
  • Bugzilla 1719964 follow up
    December 20, 2021 04:28 PST
  • Bugzilla 1719964 Mozilla resolved the ticket as fixed
    December 20, 2021 14:20 PST
  • Bugzilla 1719964 follow up
    January 08, 2022 17:56 PST
  • Bugzilla 1719964 Mozilla reply with no update
    January 09, 2022 23:55 PST
  • Mozilla confuse 1719964 (Firefox Accounts / FxA vuln with PoC) within the bug numbered 1719614 which is only related by the name 'HawkAuth' but completely separate bug where we were last looking at the Python sync server and I listed almost a hundred endpoints that needed to be validated if payload modifications are considered harmful, which would therefore permit me to demonstrate harm for them, or they could accept my bug submission on it's merits that there is clear misconfiguration with potential for harm.
    Feb 7, 2022 09:18 PST
  • I respond to point out they are confusing the 2 tickets, and clarify how 1719614 is a systematic weakness in the spec and implementation whereas 1719964 was a specific issue (remediated already).
    Feb 7, 2022 19:17 PST
  • Hall of fame status added to Bugzilla 1719964
    March 14, 2022 08:41 PDT
    No bounty payment for the bug was also noted
  • I updated Bugzilla 1719964 with details for a CVE to be issued for FXA
    March 14, 2022 08:41 PDT
  • Pull Request #12932 mozilla/fxa
    May 19, 2022, 3:53 AM GMT+10
    All mention of HawkAuth removed
  • I proposed in 1719614 that Mozilla acknowledge the systematic weakness of Hawk, their deprecation efforts, to signal publicly Mozilla have no intention of fixing the specification of HawkAuth or the libraries they maintain. Essentially an advisory to all Hawk users so that they may know they're at risk when implementing HawkAuth with it's insecure default by design.
    May 4, 2023 17:00 PDT
  • Followed up Bugzilla 1719964
    May 4, 2023 16:56 PDT
    Offered to waive bounty payment if it was a blocker for the Hall of Fame entry
  • Bugzilla 1719964 updated to reject the request for CVE on the grounds the severity is disputed, and the patch (PR#7 on mozilla-services/hawkauthlib) still hasn't been merged
    May 31, 2023 00:22 PDT
    (Not sure how a PR for another issue is related to the already patched FxA of this issue, or how severity decisions prevent the existence of a CVE, they're again confusing an issue for FXA with the other issue tracking bug in the open source HawkAuth library itself)
  • Hall of Fame confirmed for Bugzilla 1719964
    May 31, 2023 02:02 PDT
  • mozilla/hawkauthlib now officially abandoned
    Jun 1, 2023, 9:16 PM GMT+10
    The PR I raised to fix the flaw was archived along with the repo, the API spec repo mozilla/hawk was already in maintenance mode not accepting new features (the patch), so the large number of dependancies will not get a CVE or GHSA in their dependabot to advise them of the risk using this abandoned and vulnerable by default Authentication library..

Attribution via a CVE, or recognition like this is 100% all the value I sought. It's a shame the ethical outcomes could not be reached.

While the CVE process and bureaucracy makes it adversarial to raise awareness and produce a standardised way for legitimate (broken by design), widely adopted, and deprecated by the creator - kinds of vulnerabilities, you know, what CVE has as it's one purpose for existence.. Blocked by Mozilla who inappropriately block CVE creation for no apparent reason, and ignored by Mitre who we would have expected to step in but it's more like they made a 'too hard basket' when they got CNA's involved to avoid the work.