Deleted accounts leave OAuth tokens valid #8713

Closed
opened 2025-11-02 08:15:20 -06:00 by GiteaMirror · 1 comment
Owner

Originally created by @kousu on GitHub (Mar 17, 2022).

Gitea Version

Gitea version 1.16.3 built with GNU Make 4.1, go1.17.7 : bindata, sqlite, sqlite_unlock_notify

Git Version

2.25.1

Operating System

Ubuntu 20.04

How are you running Gitea?

Installed with:

# mkdir 
# useradd -m -r -d /srv/gitea gitea
# curl -L https://github.com/go-gitea/gitea/releases/download/v1.16.3/gitea-1.16.3-linux-amd64 -o /srv/gitea/gitea
# chmod +x /srv/gitea/gitea

Run manually with:

# sudo -i gitea
# ./gitea

On:

# cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.4 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

(and I have an nginx reverse proxy for TLS in front; if you want to see it's config too I can add it)

Database

PostgreSQL

Can you reproduce the bug on the Gitea demo site?

Yes

Log Gist

https://gist.github.com/kousu/7a0adf177e50bf8387a00b4fa3fd7dd3

Description

An OAuth app created by a deleted user is left behind in the database, and tokens it handed out are still valid, and can even see private repos created after the deletion.

Reproduction

  1. Make two accounts

    Account 1

    Screenshot 2022-03-16 at 19-03-49 Gitea Git with a cup of tea

    Account 2

    Screenshot 2022-03-16 at 19-04-00 Gitea Git with a cup of tea

  2. In account 1: create an OAuth app

    Screenshot 2022-03-16 at 19-20-09 Gitea Git with a cup of tea

  3. In account 2: create a couple repositories

    Screenshot 2022-03-16 at 20-43-22 bivott82

    You can see this on the demo site at: https://try.gitea.io/bivott82

  4. Deploy DroneCI (or some other OAuth consumer), providing it the OAuth app credentials.

    Get a public IP, set up DNS and open firewall ports for :80 and :443, and install docker before running this:

    docker run \
      --volume=/var/lib/drone:/data \
      --env=DRONE_GITEA_SERVER=https://try.gitea.io \
      --env=DRONE_GITEA_CLIENT_ID=4d9b78ea-d8fc-45ed-a11a-ea684a690108 \
      --env=DRONE_GITEA_CLIENT_SECRET=gto_z5tbfeunl4g752hlj5aeoksj25jev7lxblzejdop5sxt76nmacvq \
      --env=DRONE_RPC_SECRET="$(openssl rand -hex 16)" \
      --env=DRONE_SERVER_HOST=drone1.kousu.ca \
      --env=DRONE_SERVER_PROTO=https \
      --env=DRONE_TLS_AUTOCERT=true \
      --publish=80:80 \
      --publish=443:443 \
      --restart=always \
      --detach=true \
      --name=drone \
      drone/drone:2
    
  5. In account 2: login to DroneCI; you will see the two repositories:

    Screenshot 2022-03-16 at 20-44-09 Drone CI

    Screenshot 2022-03-16 at 20-44-19 Gitea Git with a cup of tea

    Screenshot 2022-03-16 at 20-44-46 Drone CI
    Screenshot 2022-03-16 at 20-44-53 Drone CI

  6. In account 1: delete account

    Screenshot 2022-03-16 at 20-48-38 Gitea Git with a cup of tea

  7. In account 1: create a third repository

    Screenshot 2022-03-16 at 20-49-08 Gitea Git with a cup of tea

    You can see this on the demo site at: https://try.gitea.io/bivott82

  8. In DroneCI: refresh

    Screenshot 2022-03-16 at 20-49-33 Drone CI

    You will: incorrectly see the third repository.

    Screenshot 2022-03-16 at 20-49-44 Drone CI

  9. Log out of DroneCI

    Screenshot 2022-03-16 at 20-49-59 Account - Drone CI

  10. Try to login again:

    Screenshot 2022-03-16 at 20-50-13 Drone CI

    You will: get a half-correct HTTP 500 error from Gitea.

    Screenshot 2022-03-16 at 20-50-22 Gitea Git with a cup of tea

    You should be able to see this screen on the demo site at:
    https://try.gitea.io/login/oauth/authorize?client_id=4d9b78ea-d8fc-45ed-a11a-ea684a690108&redirect_uri=https%3A%2F%2Fdrone1.kousu.ca%2Flogin&response_type=code&state=30b95ff183c471d4

  11. If you can look in the database:

    You will: see the oauth2_application is still recorded.

    # sudo -u gitea psql -c 'select * from oauth2_application' | tee /dev/null
    id | uid |  name   |              client_id               |                        client_secret                         |           redirect_uris            | created_unix | updated_unix 
    ----+-----+---------+--------------------------------------+--------------------------------------------------------------+------------------------------------+--------------+--------------
      1 |   5 | DroneCI | 3cb8ec3b-5140-4875-bffa-716f9cf1cef7 | $2a$10$L6nyevnaNwKNB3cZc6rhUenodOlZ2DNFr4wIM.jPIP9BULRHRP8QW | ["http://3.98.145.180:8080/login"] |   1647449740 |   1647452962
    (1 row)
    

    even though the associated uid is gone:

    # sudo -u gitea psql -c 'select id,name from public.user where id=5;' | tee /dev/null
    id | name 
    ----+------
    (0 rows)
    

Expected Behaviour

I would expect that deleting a user would delete all access rights that user had.

So, I would expect that deleting a user would delete all OAuth apps in their name and immediately revoke all tokens that were given out to it. The tokens not being revoked means a user can leave a ghost app around, at least

Right now you apparently can't get a new OAuth token issued (👍), but previously issued ones are still valid (👎), meaning someone who phished you into opening their malicious app can hide their tracks.

The HTTP 500 should instead be the standard HTTP 400 with "Client ID not registered":

Screenshot 2022-03-16 at 22-03-51 Gitea Git with a cup of tea

and clicking "Sync" on Drone (or any similar app) should fail.

Originally created by @kousu on GitHub (Mar 17, 2022). ### Gitea Version Gitea version 1.16.3 built with GNU Make 4.1, go1.17.7 : bindata, sqlite, sqlite_unlock_notify ### Git Version 2.25.1 ### Operating System Ubuntu 20.04 ### How are you running Gitea? Installed with: ``` # mkdir # useradd -m -r -d /srv/gitea gitea # curl -L https://github.com/go-gitea/gitea/releases/download/v1.16.3/gitea-1.16.3-linux-amd64 -o /srv/gitea/gitea # chmod +x /srv/gitea/gitea ``` Run manually with: ``` # sudo -i gitea # ./gitea ``` On: ``` # cat /etc/os-release NAME="Ubuntu" VERSION="20.04.4 LTS (Focal Fossa)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 20.04.4 LTS" VERSION_ID="20.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" VERSION_CODENAME=focal UBUNTU_CODENAME=focal ``` (and I have an nginx reverse proxy for TLS in front; if you want to see it's config too I can add it) ### Database PostgreSQL ### Can you reproduce the bug on the Gitea demo site? Yes ### Log Gist https://gist.github.com/kousu/7a0adf177e50bf8387a00b4fa3fd7dd3 ### Description An OAuth app created by a deleted user is left behind in the database, and tokens it handed out are still valid, and can even see **private repos** created **after** the deletion. ### Reproduction 1. Make two accounts <details><summary>Account 1</summary> ![Screenshot 2022-03-16 at 19-03-49 Gitea Git with a cup of tea](https://user-images.githubusercontent.com/987487/158715198-9be5fe89-7bf4-49ad-a584-a7248e5c596b.png) </details> <details><summary>Account 2</summary> ![Screenshot 2022-03-16 at 19-04-00 Gitea Git with a cup of tea](https://user-images.githubusercontent.com/987487/158715201-47a697c5-c6c9-4670-82b4-71264fa881d8.png) </details> 2. In account 1: create an OAuth app <details> ![Screenshot 2022-03-16 at 19-20-09 Gitea Git with a cup of tea](https://user-images.githubusercontent.com/987487/158715204-ee06aee1-258b-4ed9-ba6e-46cf5023f344.png) </details> 3. In account 2: create a couple repositories <details> ![Screenshot 2022-03-16 at 20-43-22 bivott82](https://user-images.githubusercontent.com/987487/158715207-a2a4cdca-3887-4b30-9af2-e5955a30811a.png) </details> _You can see this on the demo site at_: https://try.gitea.io/bivott82 2. Deploy DroneCI (or some other OAuth consumer), providing it the OAuth app credentials. Get a public IP, set up DNS and open firewall ports for :80 and :443, and install docker before running this: ``` docker run \ --volume=/var/lib/drone:/data \ --env=DRONE_GITEA_SERVER=https://try.gitea.io \ --env=DRONE_GITEA_CLIENT_ID=4d9b78ea-d8fc-45ed-a11a-ea684a690108 \ --env=DRONE_GITEA_CLIENT_SECRET=gto_z5tbfeunl4g752hlj5aeoksj25jev7lxblzejdop5sxt76nmacvq \ --env=DRONE_RPC_SECRET="$(openssl rand -hex 16)" \ --env=DRONE_SERVER_HOST=drone1.kousu.ca \ --env=DRONE_SERVER_PROTO=https \ --env=DRONE_TLS_AUTOCERT=true \ --publish=80:80 \ --publish=443:443 \ --restart=always \ --detach=true \ --name=drone \ drone/drone:2 ``` 5. In account 2: login to DroneCI; you will see the two repositories: <details> ![Screenshot 2022-03-16 at 20-44-09 Drone CI](https://user-images.githubusercontent.com/987487/158715209-79195cbb-e63b-469a-9f21-66301878aa09.png) ![Screenshot 2022-03-16 at 20-44-19 Gitea Git with a cup of tea](https://user-images.githubusercontent.com/987487/158715213-112e2b6a-de9e-4d1c-a7c8-b4d376fa8dfe.png) ![Screenshot 2022-03-16 at 20-44-46 Drone CI](https://user-images.githubusercontent.com/987487/158715216-ab874bca-aae0-4d62-a9a9-8ef94d56192e.png) ![Screenshot 2022-03-16 at 20-44-53 Drone CI](https://user-images.githubusercontent.com/987487/158715218-6e69943d-d06e-451a-b418-9e0249facb70.png) </details> 3. In account 1: delete account <details> ![Screenshot 2022-03-16 at 20-48-38 Gitea Git with a cup of tea](https://user-images.githubusercontent.com/987487/158715222-9247e0dc-9a94-4fb7-bc92-9e05930f1926.png) </details> 5. In account 1: create a third repository <details> ![Screenshot 2022-03-16 at 20-49-08 Gitea Git with a cup of tea](https://user-images.githubusercontent.com/987487/158715223-cf8f3eee-cf48-4554-bed7-21f2495c4aac.png) </details> _You can see this on the demo site at_: https://try.gitea.io/bivott82 7. In DroneCI: refresh <details> ![Screenshot 2022-03-16 at 20-49-33 Drone CI](https://user-images.githubusercontent.com/987487/158715226-3bb2f8c6-b46e-4b29-90e9-2b97a8e83a43.png) </details> You will: **incorrectly** see the third repository. <details> ![Screenshot 2022-03-16 at 20-49-44 Drone CI](https://user-images.githubusercontent.com/987487/158715229-a8675244-e1f4-4a2f-abb5-85ad439bbb01.png) </details> 9. Log out of DroneCI <details> ![Screenshot 2022-03-16 at 20-49-59 Account - Drone CI](https://user-images.githubusercontent.com/987487/158715230-6b5f4c54-aa61-4c89-8192-775a7aa8d2ec.png) </details> 11. Try to login again: <details> ![Screenshot 2022-03-16 at 20-50-13 Drone CI](https://user-images.githubusercontent.com/987487/158715232-37ca1b99-115b-4acf-8f34-460f4fe43f57.png) </details> You will: get a **half**-correct HTTP 500 error from Gitea. <details> ![Screenshot 2022-03-16 at 20-50-22 Gitea Git with a cup of tea](https://user-images.githubusercontent.com/987487/158715234-4fc3961a-b2b1-46ad-bd32-83b2d14f0c4b.png) </details> **You should be able to see this screen on the demo site at:** https://try.gitea.io/login/oauth/authorize?client_id=4d9b78ea-d8fc-45ed-a11a-ea684a690108&redirect_uri=https%3A%2F%2Fdrone1.kousu.ca%2Flogin&response_type=code&state=30b95ff183c471d4 13. If you can look in the database: You will: see the `oauth2_application` is still recorded. ``` # sudo -u gitea psql -c 'select * from oauth2_application' | tee /dev/null id | uid | name | client_id | client_secret | redirect_uris | created_unix | updated_unix ----+-----+---------+--------------------------------------+--------------------------------------------------------------+------------------------------------+--------------+-------------- 1 | 5 | DroneCI | 3cb8ec3b-5140-4875-bffa-716f9cf1cef7 | $2a$10$L6nyevnaNwKNB3cZc6rhUenodOlZ2DNFr4wIM.jPIP9BULRHRP8QW | ["http://3.98.145.180:8080/login"] | 1647449740 | 1647452962 (1 row) ``` even though the associated `uid` is gone: ``` # sudo -u gitea psql -c 'select id,name from public.user where id=5;' | tee /dev/null id | name ----+------ (0 rows) ``` ### Expected Behaviour I would expect that deleting a user would delete all access rights that user had. So, I would expect that deleting a user would delete all OAuth apps in their name **and immediately revoke** all tokens that were given out to it. The tokens not being revoked means a user can leave a ghost app around, at least Right now you apparently can't get a new OAuth token issued (:+1:), but previously issued ones are still valid (:-1:), meaning someone who phished you into opening their malicious app can hide their tracks. The HTTP 500 **should** instead be the standard HTTP 400 with "Client ID not registered": ![Screenshot 2022-03-16 at 22-03-51 Gitea Git with a cup of tea](https://user-images.githubusercontent.com/987487/158721915-ff8636ad-7621-4931-8711-1b5444aadcdb.png) and clicking "Sync" on Drone (or any similar app) **should fail**.
GiteaMirror added the topic/security label 2025-11-02 08:15:20 -06:00
Author
Owner

@kousu commented on GitHub (May 11, 2022):

Thank you for looking into and taking care of this @6543 :)

@kousu commented on GitHub (May 11, 2022): Thank you for looking into and taking care of this @6543 :)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea#8713