Codeberg/Community
60
387
Fork
You've already forked Community
12

cannot clone repositories from a web page git client, because of CORS, even though it "definitely" should work #2745

Open
opened 2026年06月09日 23:15:15 +02:00 by ArcaneNibble · 4 comments

Comment

For background context see here

I am attempting to clone a repository on Codeberg using the isomorphic-git library, which is a pure-JavaScript git client which is able to run in a web browser. I am including the library in a custom test app which is hosted by the webpack dev server on http://127.0.0.1:8080/

When I try to clone a repository, I find that it is blocked by CORS:

Screen Shot of CORS error

Indeed, if I try to copy the request as cURL and perform it manually, I see:

$ curl --output - -v 'https://codeberg.org/ArcaneNibble/test2/info/refs?service=git-upload-pack' \
 -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0' \
 -H 'Accept: */*' \
 -H 'Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh-HK;q=0.7,zh;q=0.6' \
 -H 'Accept-Encoding: gzip, deflate, br, zstd' \
 -H 'Referer: http://127.0.0.1:8080/' \
 -H 'Origin: http://127.0.0.1:8080' \
 -H 'DNT: 1' \
 -H 'Sec-GPC: 1' \
 -H 'Connection: keep-alive' \
 -H 'Sec-Fetch-Dest: empty' \
 -H 'Sec-Fetch-Mode: cors' \
 -H 'Sec-Fetch-Site: cross-site' \
 -H 'Priority: u=4' \
 -H 'TE: trailers'
* Trying 2a0a:4580:103f:c0de::1:443...
* Connected to codeberg.org (2a0a:4580:103f:c0de::1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /Users/rqou/code/emsdk/python/3.9.2_64bit/lib/python3.9/site-packages/certifi/cacert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=*.codeberg.org
* start date: Apr 15 11:09:01 2026 GMT
* expire date: Jul 14 11:09:00 2026 GMT
* subjectAltName: host "codeberg.org" matched cert's "codeberg.org"
* issuer: C=US; O=Let's Encrypt; CN=E8
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x12d811200)
> GET /ArcaneNibble/test2/info/refs?service=git-upload-pack HTTP/2
> Host: codeberg.org
> user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0
> accept: */*
> accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh-HK;q=0.7,zh;q=0.6
> accept-encoding: gzip, deflate, br, zstd
> referer: http://127.0.0.1:8080/
> origin: http://127.0.0.1:8080
> dnt: 1
> sec-gpc: 1
> connection: keep-alive
> sec-fetch-dest: empty
> sec-fetch-mode: cors
> sec-fetch-site: cross-site
> priority: u=4
> te: trailers
>
< HTTP/2 200
< cache-control: no-cache, max-age=0, must-revalidate
< content-type: application/x-git-upload-pack-advertisement
< expires: 1980年1月01日 00:00:00 GMT
< pragma: no-cache
< x-frame-options: SAMEORIGIN
< content-length: 425
< date: 2026年6月09日 21:07:06 GMT
< x-server-name: s_forgejo_secondary_alpspitz
< strict-transport-security: max-age=63072000; includeSubDomains; preload;
< permissions-policy: interest-cohort=()
< alt-svc: h3=":443";ma=2592000;
<
001e# service=git-upload-pack
00000146d5ebd35b093ad1597f3d4d40988466aa2ce667de HEADmulti_ack thin-pack side-band side-band-64k ofs-delta shallow deepen-since deepen-not deepen-relative no-progress include-tag multi_ack_detailed allow-tip-sha1-in-want allow-reachable-sha1-in-want no-done symref=HEAD:refs/heads/main filter object-format=sha1 agent=git/2.47.3
003dd5ebd35b093ad1597f3d4d40988466aa2ce667de refs/heads/main
* Connection #0 to host codeberg.org left intact

There are indeed no CORS headers in the response.

If we allow the use of parallel universes where I have implemented a CORS proxy, the subsequent request that would be made would be:

$ curl --output - -v 'https://codeberg.org/ArcaneNibble/test2/git-upload-pack' \
 -X POST \
 -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0' \
 -H 'Accept: application/x-git-upload-pack-result' \
 -H 'Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh-HK;q=0.7,zh;q=0.6' \
 -H 'Accept-Encoding: gzip, deflate, br, zstd' \
 -H 'Referer: http://127.0.0.1:8080/' \
 -H 'content-type: application/x-git-upload-pack-request' \
 -H 'Origin: http://127.0.0.1:8080' \
 -H 'DNT: 1' \
 -H 'Sec-GPC: 1' \
 -H 'Connection: keep-alive' \
 -H 'Sec-Fetch-Dest: empty' \
 -H 'Sec-Fetch-Mode: cors' \
 -H 'Sec-Fetch-Site: cross-site' \
 -H 'Priority: u=4' \
 -H 'TE: trailers' \
 --data-raw $'0085want d5ebd35b093ad1597f3d4d40988466aa2ce667de multi_ack_detailed no-done side-band-64k ofs-delta agent=git/isomorphic-git@1.38.4\n000edeepen 10\n00000009done\n'
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 2a0a:4580:103f:c0de::1:443...
* Connected to codeberg.org (2a0a:4580:103f:c0de::1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /Users/rqou/code/emsdk/python/3.9.2_64bit/lib/python3.9/site-packages/certifi/cacert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=*.codeberg.org
* start date: Apr 15 11:09:01 2026 GMT
* expire date: Jul 14 11:09:00 2026 GMT
* subjectAltName: host "codeberg.org" matched cert's "codeberg.org"
* issuer: C=US; O=Let's Encrypt; CN=E8
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x15a00d400)
> POST /ArcaneNibble/test2/git-upload-pack HTTP/2
> Host: codeberg.org
> user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0
> accept: application/x-git-upload-pack-result
> accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh-HK;q=0.7,zh;q=0.6
> accept-encoding: gzip, deflate, br, zstd
> referer: http://127.0.0.1:8080/
> content-type: application/x-git-upload-pack-request
> origin: http://127.0.0.1:8080
> dnt: 1
> sec-gpc: 1
> connection: keep-alive
> sec-fetch-dest: empty
> sec-fetch-mode: cors
> sec-fetch-site: cross-site
> priority: u=4
> te: trailers
> content-length: 160
>
* We are completely uploaded and fine
< HTTP/2 200
< cache-control: max-age=0, private, must-revalidate, no-transform
< content-type: application/x-git-upload-pack-result
< x-frame-options: SAMEORIGIN
< content-length: 493
< date: 2026年6月09日 21:11:59 GMT
< x-server-name: s_forgejo_main
< strict-transport-security: max-age=63072000; includeSubDomains; preload;
< permissions-policy: interest-cohort=()
< alt-svc: h3=":443";ma=2592000;
<
00000008NAK
0023Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
0043Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
00e7PACK<binary data omitted>

Again there are no CORS headers.

While attempting to report the issue as an upstream Forgejo issue, I was told that this "definitely" should work, so I'm assuming this is an issue with Codeberg's deployment specifically.

### Comment For background context see [here](https://codeberg.org/forgejo/forgejo/issues/13026) I am attempting to clone a repository on Codeberg using the [isomorphic-git](https://isomorphic-git.org/) library, which is a pure-JavaScript git client which is able to run in a web browser. I am including the library in a custom test app which is hosted by the [webpack](https://webpack.js.org/) dev server on `http://127.0.0.1:8080/` When I try to clone a repository, I find that it is blocked by CORS: ![Screen Shot of CORS error](/attachments/a2748e70-3150-4d5b-82b8-629a226d34a2) Indeed, if I try to copy the request as cURL and perform it manually, I see: ``` $ curl --output - -v 'https://codeberg.org/ArcaneNibble/test2/info/refs?service=git-upload-pack' \ -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0' \ -H 'Accept: */*' \ -H 'Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh-HK;q=0.7,zh;q=0.6' \ -H 'Accept-Encoding: gzip, deflate, br, zstd' \ -H 'Referer: http://127.0.0.1:8080/' \ -H 'Origin: http://127.0.0.1:8080' \ -H 'DNT: 1' \ -H 'Sec-GPC: 1' \ -H 'Connection: keep-alive' \ -H 'Sec-Fetch-Dest: empty' \ -H 'Sec-Fetch-Mode: cors' \ -H 'Sec-Fetch-Site: cross-site' \ -H 'Priority: u=4' \ -H 'TE: trailers' * Trying 2a0a:4580:103f:c0de::1:443... * Connected to codeberg.org (2a0a:4580:103f:c0de::1) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /Users/rqou/code/emsdk/python/3.9.2_64bit/lib/python3.9/site-packages/certifi/cacert.pem * CApath: none * (304) (OUT), TLS handshake, Client hello (1): * (304) (IN), TLS handshake, Server hello (2): * (304) (IN), TLS handshake, Unknown (8): * (304) (IN), TLS handshake, Certificate (11): * (304) (IN), TLS handshake, CERT verify (15): * (304) (IN), TLS handshake, Finished (20): * (304) (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256 * ALPN, server accepted to use h2 * Server certificate: * subject: CN=*.codeberg.org * start date: Apr 15 11:09:01 2026 GMT * expire date: Jul 14 11:09:00 2026 GMT * subjectAltName: host "codeberg.org" matched cert's "codeberg.org" * issuer: C=US; O=Let's Encrypt; CN=E8 * SSL certificate verify ok. * Using HTTP2, server supports multiplexing * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x12d811200) > GET /ArcaneNibble/test2/info/refs?service=git-upload-pack HTTP/2 > Host: codeberg.org > user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0 > accept: */* > accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh-HK;q=0.7,zh;q=0.6 > accept-encoding: gzip, deflate, br, zstd > referer: http://127.0.0.1:8080/ > origin: http://127.0.0.1:8080 > dnt: 1 > sec-gpc: 1 > connection: keep-alive > sec-fetch-dest: empty > sec-fetch-mode: cors > sec-fetch-site: cross-site > priority: u=4 > te: trailers > < HTTP/2 200 < cache-control: no-cache, max-age=0, must-revalidate < content-type: application/x-git-upload-pack-advertisement < expires: 1980年1月01日 00:00:00 GMT < pragma: no-cache < x-frame-options: SAMEORIGIN < content-length: 425 < date: 2026年6月09日 21:07:06 GMT < x-server-name: s_forgejo_secondary_alpspitz < strict-transport-security: max-age=63072000; includeSubDomains; preload; < permissions-policy: interest-cohort=() < alt-svc: h3=":443";ma=2592000; < 001e# service=git-upload-pack 00000146d5ebd35b093ad1597f3d4d40988466aa2ce667de HEADmulti_ack thin-pack side-band side-band-64k ofs-delta shallow deepen-since deepen-not deepen-relative no-progress include-tag multi_ack_detailed allow-tip-sha1-in-want allow-reachable-sha1-in-want no-done symref=HEAD:refs/heads/main filter object-format=sha1 agent=git/2.47.3 003dd5ebd35b093ad1597f3d4d40988466aa2ce667de refs/heads/main * Connection #0 to host codeberg.org left intact ``` There are indeed no CORS headers in the response. If we allow the use of parallel universes where I have implemented a CORS proxy, the subsequent request that would be made would be: ``` $ curl --output - -v 'https://codeberg.org/ArcaneNibble/test2/git-upload-pack' \ -X POST \ -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0' \ -H 'Accept: application/x-git-upload-pack-result' \ -H 'Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh-HK;q=0.7,zh;q=0.6' \ -H 'Accept-Encoding: gzip, deflate, br, zstd' \ -H 'Referer: http://127.0.0.1:8080/' \ -H 'content-type: application/x-git-upload-pack-request' \ -H 'Origin: http://127.0.0.1:8080' \ -H 'DNT: 1' \ -H 'Sec-GPC: 1' \ -H 'Connection: keep-alive' \ -H 'Sec-Fetch-Dest: empty' \ -H 'Sec-Fetch-Mode: cors' \ -H 'Sec-Fetch-Site: cross-site' \ -H 'Priority: u=4' \ -H 'TE: trailers' \ --data-raw $'0085want d5ebd35b093ad1597f3d4d40988466aa2ce667de multi_ack_detailed no-done side-band-64k ofs-delta agent=git/isomorphic-git@1.38.4\n000edeepen 10\n00000009done\n' Note: Unnecessary use of -X or --request, POST is already inferred. * Trying 2a0a:4580:103f:c0de::1:443... * Connected to codeberg.org (2a0a:4580:103f:c0de::1) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /Users/rqou/code/emsdk/python/3.9.2_64bit/lib/python3.9/site-packages/certifi/cacert.pem * CApath: none * (304) (OUT), TLS handshake, Client hello (1): * (304) (IN), TLS handshake, Server hello (2): * (304) (IN), TLS handshake, Unknown (8): * (304) (IN), TLS handshake, Certificate (11): * (304) (IN), TLS handshake, CERT verify (15): * (304) (IN), TLS handshake, Finished (20): * (304) (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256 * ALPN, server accepted to use h2 * Server certificate: * subject: CN=*.codeberg.org * start date: Apr 15 11:09:01 2026 GMT * expire date: Jul 14 11:09:00 2026 GMT * subjectAltName: host "codeberg.org" matched cert's "codeberg.org" * issuer: C=US; O=Let's Encrypt; CN=E8 * SSL certificate verify ok. * Using HTTP2, server supports multiplexing * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x15a00d400) > POST /ArcaneNibble/test2/git-upload-pack HTTP/2 > Host: codeberg.org > user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:151.0) Gecko/20100101 Firefox/151.0 > accept: application/x-git-upload-pack-result > accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh-HK;q=0.7,zh;q=0.6 > accept-encoding: gzip, deflate, br, zstd > referer: http://127.0.0.1:8080/ > content-type: application/x-git-upload-pack-request > origin: http://127.0.0.1:8080 > dnt: 1 > sec-gpc: 1 > connection: keep-alive > sec-fetch-dest: empty > sec-fetch-mode: cors > sec-fetch-site: cross-site > priority: u=4 > te: trailers > content-length: 160 > * We are completely uploaded and fine < HTTP/2 200 < cache-control: max-age=0, private, must-revalidate, no-transform < content-type: application/x-git-upload-pack-result < x-frame-options: SAMEORIGIN < content-length: 493 < date: 2026年6月09日 21:11:59 GMT < x-server-name: s_forgejo_main < strict-transport-security: max-age=63072000; includeSubDomains; preload; < permissions-policy: interest-cohort=() < alt-svc: h3=":443";ma=2592000; < 00000008NAK 0023Enumerating objects: 3, done. Counting objects: 100% (3/3), done. 0043Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0) 00e7PACK<binary data omitted> ``` Again there are no CORS headers. While attempting to report the issue as an upstream Forgejo issue, I was told that this "definitely" should work, so I'm assuming this is an issue with Codeberg's deployment specifically.

It seems the cors setting slightly changed since we enabled CORS years ago. That said, there's a big security warning on enabling this, this requires further investigation if this can be enabled safely on Codeberg.

It seems the cors setting slightly changed since we enabled CORS years ago. That said, there's a big security warning on enabling this, this requires further investigation if this can be enabled safely on Codeberg.

Yeah, I'm also doing some digging and it seems this setting is controlled by ACCESS_CONTROL_ALLOW_ORIGIN under [repository] rather than by [cors]

I'm not sure what exactly

WARNING: This may be harmful to your website if you do not give it the correct value.

is supposed to be referring to though

Yeah, I'm also doing some digging and it seems this setting is controlled by `ACCESS_CONTROL_ALLOW_ORIGIN` under `[repository]` rather than by `[cors]` I'm not sure what exactly > WARNING: This may be harmful to your website if you do not give it the correct value. is supposed to be referring to though

I think this should be safe to enable:

  • credentialed GET requests aren't compatible with Access-Control-Allow-Origin: * (so another site can't read data it shouldn't)
  • the actual git smart HTTP protocol requires custom content types which must be preflighted (so another site can't blindly send POSTs hoping to push changes into git)

I do see some things which feel kinda sketchy though (although it should still be fine):

  • the git smart protocol normally uses basic auth, but the site UI uses cookie auth. it shouldn't be possible to mix them up, but /info/refs?service=git-upload-pack does accept cookie auth too (a cross-origin request with credentials still shouldn't be able to read the result though)
  • trying to access /info/refs?service=git-upload-pack in a web browser does cause the browser to ask for a username and password, so it is possible to end up with ambient credentials

perhaps these issues could be hardened in Forgejo?

I think this should be safe to enable: - credentialed GET requests aren't compatible with `Access-Control-Allow-Origin: *` (so another site can't read data it shouldn't) - the actual git smart HTTP protocol requires custom content types which must be preflighted (so another site can't blindly send POSTs hoping to push changes into git) I do see some things which feel kinda sketchy though (although it should still be fine): - the git smart protocol normally uses basic auth, but the site UI uses cookie auth. it shouldn't be possible to mix them up, but `/info/refs?service=git-upload-pack` does accept cookie auth too (a cross-origin request with credentials still shouldn't be able to read the result though) - trying to access `/info/refs?service=git-upload-pack` in a web browser does cause the browser to ask for a username and password, so it _is_ possible to end up with ambient credentials perhaps these issues could be hardened in Forgejo?

There is, of course, the definitely safe option of having an entirely separate domain/origin for this specific use case (either built-in or by hosting a CORS proxy)

There is, of course, the definitely safe option of having an entirely separate domain/origin for this specific use case (either built-in or by hosting a CORS proxy)
Sign in to join this conversation.
No Branch/Tag specified
main
No results found.
Labels
Clear labels
accessibility
Reduces accessibility and is thus a "bug" for certain user groups on Codeberg.
bug
Something is not working the way it should. Does not concern outages.
bug
infrastructure
Errors evidently caused by infrastructure malfunctions or outages
Codeberg
This issue involves Codeberg's downstream modifications and settings and/or Codeberg's structures.
contributions welcome
Please join the discussion and consider contributing a PR!
docs
No bug, but an improvement to the docs or UI description will help
duplicate
This issue or pull request already exists
enhancement
New feature
infrastructure
Involves changes to the server setups, use `bug/infrastructure` for infrastructure-related user errors.
legal
An issue directly involving legal compliance
licence / ToS
involving questions about the ToS, especially licencing compliance
please chill
we are volunteers
Please consider editing your posts and remember that there is a human on the other side. We get that you are frustrated, but it's harder for us to help you this way.
public relations
Things related to Codeberg's external communication
question
More information is needed
question
user support
This issue contains a clearly stated problem. However, it is not clear whether we have to fix anything on Codeberg's end, but we're helping them fix it and/or find the cause.
s/Forgejo
Related to Forgejo. Please also check Forgejo's issue tracker.
s/Forgejo/migration
Migration related issues in Forgejo
s/Pages
Issues related to the Codeberg Pages feature
s/Weblate
Issue is related to the Weblate instance at https://translate.codeberg.org
s/Woodpecker
Woodpecker CI related issue
security
involves improvements to the sites security
service
Add a new service to the Codeberg ecosystem (instead of implementing into Forgejo)
upstream
An open issue or pull request to an upstream repository to fix this issue (partially or completely) exists (i.e. Forgejo, Weblate, etc.)
wontfix
Codeberg's current set of contributors are not planning to spend time on delegating this issue.
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Codeberg/Community#2745
Reference in a new issue
Codeberg/Community
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?