Home

  • Bypassing Warp’s login requirement

    I recently came across an application called Warp (warp.dev) that claims to be a “blazingly fast, Rust-based terminal” and is “fully native”. It has some interesting features such as blocks to separate the output of different commands.

    It comes with some extra things though: required login and forced telemetry. The latter can be blocked with a firewall such as Little Snitch. However the former requires some more work to bypass.

    When I first downloaded it and saw that it required a login, I almost decided to just trash it (as would most people I imagine). But I figured I might instead create an account so I can see how much effort it would take to force it to run with no details.

    Warp has configuration data in 3 places (that I know of):

    • ~/Library/Application Support/dev.warp.Warp-Stable
    • ~/Library/Preferences/dev.warp.Warp-Stable.plist
    • An application password entry in the “login” keychain

    The directory in “Application Support” has an SQLite database called warp.sqlite, but it contains no interesting details about logins or sessions or related things. (It also had a file called telemetry_events.json which was an empty list – I imagine this would have more details if I didn’t block Warp’s network connections)

    The plist has at least 4 keys: Shortcuts, FontSize, SystemTheme, and ChangelogVersions.

    After I didn’t find any details here, I looked online and found out that Warp uses the keychain for login information. This makes sense, I guess I’m not used to messing with the keychain (most of the applications I use don’t use it).

    Warp’s addition in Keychain Access.

    The “password” in the keychain entry is JSON containing login details. The format looks like this after I logged in with GitHub (formatted for readability):

    {
        "id_token": {
            "id_token": "xxx",
            "refresh_token": "xxx",
            "expiration_time": "2022-07-10T00:50:24.964731-07:00"
        },
        "refresh_token": "xxx",
        "local_id": "xxx",
        "email": "example@example.com",
        "display_name": "ihaveahax",
        "photo_url": "https://avatars.githubusercontent.com/u/590576?v=4",
        "screen_name": "ihaveamac"
    }
    

    So the question now is, how many of these can I change until Warp stops letting me into the actual terminal? I started poking at this by inserting custom JSON into the keychain.

    The security command has the ability to view, add, and delete stuff from the Mac keychain. (To view Warp’s entry: security find-generic-password -s 'dev.warp.Warp-Stable' -g)

    I made a quick custom script to make it easy to generate JSON and modify the keychain entry. After some prodding, I figured out the minimal amount of data required is only “expiration_time“. Every other key can be empty.

    {"display_name":"","email":"","id_token":{"expiration_time":"2022-07-10T00:50:24.964731-07:00","id_token":"","refresh_token":""},"local_id":"","photo_url":"","refresh_token":"","screen_name":""}
    

    This can be inserted into the keychain with one command:

    security add-generic-password -a 'User' -s 'dev.warp.Warp-Stable' -U -w '{"display_name":"","email":"","id_token":{"expiration_time":"2022-07-10T00:50:24.964731-07:00","id_token":"","refresh_token":""},"local_id":"","photo_url":"","refresh_token":"","screen_name":""}'
    

    This will probably change in the future if they decide to tighten the restrictions on logins, but for the time being one can use the offline features of Warp without giving any data to the developers. (Except for whatever I had to give to get past the first step.)

    (It’s worth pointing out that Warp is a company that received $23 million from venture capital funding.)


    This is the script to generate and insert into the keychain.

    from json import dumps
    from subprocess import run
    
    data = {'display_name': 'ihaveahax',
     'email': 'ian@ianburgwin.net',
     'id_token': {'expiration_time': '2022-07-10T00:50:24.964731-07:00',
                  'id_token': 'xxx',
                  'refresh_token': 'xxx'},
     'local_id': 'xxx',
     'photo_url': 'https://avatars.githubusercontent.com/u/590576?v=4',
     'refresh_token': 'xxx',
     'screen_name': 'ihaveamac'}
    
    data['id_token']['id_token'] = ''
    data['id_token']['refresh_token'] = ''
    #data['id_token']['expiration_time'] = ''
    #data['id_token']['expiration_time'] = 'a'
    data['local_id'] = ''
    data['refresh_token'] = ''
    data['photo_url'] = ''
    data['email'] = ''
    data['screen_name'] = ''
    data['display_name'] = ''
    
    run(['security', 'add-generic-password', '-a', 'User', '-s', 'dev.warp.Warp-Stable', '-U', '-w', dumps(data)])