Skip to content

Bug: Don't generate a public link token for internal circle team share#2443

Open
T0mWz wants to merge 4 commits intonextcloud:masterfrom
T0mWz:public-link-token-not-generated-for-team-share
Open

Bug: Don't generate a public link token for internal circle team share#2443
T0mWz wants to merge 4 commits intonextcloud:masterfrom
T0mWz:public-link-token-not-generated-for-team-share

Conversation

@T0mWz
Copy link
Copy Markdown

@T0mWz T0mWz commented Apr 15, 2026

Issue

When sharing data with a team, a public link token is inadvertently generated alongside the secure internal share link for authenticated users. This public link has the same access rights and, until recently, was shared with team members via email.
Although the recipients were already authorised to access this data, recipients of the email may have forwarded it to third parties, thereby allowing them – without authorisation – to gain access with the same rights as an authorised person. Team members are no longer informed of this, but a public link token is still generated behind the scenes.

This public link token can easily be guessed using a randomiser, thereby allowing unauthorised access to data that should not have been publicly accessible.

How to reproduce
Create a team via the contacts. Then share a dataset with custom permissions with this team.

** Result **

MariaDB [nextcloud]> select * from oc_share where id = '16135' \G;
*************************** 1. row ***************************
                      id: 16135
              share_type: 7
              share_with: ax1Gvs4s964zpZR5z7kyXgbzd9QPXnh
               uid_owner: piet
           uid_initiator: piet
                  parent: NULL
               item_type: folder
             item_source: 6946132
             item_target: NULL
             file_source: 6946132
             file_target: /Test_Public_Link_Breach
             permissions: 31
                   stime: 1776062454
                accepted: 1
              expiration: NULL
                   token: 8ui9FePpNwznze8
               mail_send: 1
              share_name: NULL
                password:
        password_by_talk: 0
                    note: Bla
           hide_download: 0
                   label: NULL
              attributes: [["permissions","download",true]]
password_expiration_time: NULL
           reminder_sent: 0
1 row in set (0.000 sec)

You can view this data without authentication via the public link token (8ui9FePpNwznze8), with the assumption that it has only been shared with team members via authorised access.

@T0mWz
Copy link
Copy Markdown
Author

T0mWz commented Apr 15, 2026

This issue is related to pull request; #2390

@T0mWz
Copy link
Copy Markdown
Author

T0mWz commented Apr 15, 2026

@cristianscheid please can you review this?

@T0mWz T0mWz changed the title Don't generate a public link token without password protection Don't generate a public link token for internal circle team share Apr 15, 2026
@T0mWz T0mWz changed the title Don't generate a public link token for internal circle team share Bug: Don't generate a public link token for internal circle team share Apr 15, 2026
@cristianscheid
Copy link
Copy Markdown
Contributor

Hi @T0mWz, thanks for the PR! I'm currently reviewing and testing the impact of this fix. I'll keep you posted.

@cristianscheid
Copy link
Copy Markdown
Contributor

After testing the fix locally, I found it introduces a new bug when sharing a folder with a team that has members added by email (like below).
image
When trying to access the link sent to those users, they no longer work as expected. I'm still investigating the impacts of this fix on teams that include federated users.

@T0mWz
Copy link
Copy Markdown
Author

T0mWz commented Apr 21, 2026

Hi @cristianscheid ,

Sorry for my late reply. You’re absolutely right. I hadn’t tested this properly either; I can now see the Internal Server Error on my end too, although it’s still with NC32.

With Nextcloud Circles, a share can be created with users within Nextcloud. However, external users can also be added based on their email address.

When sharing via a Nextcloud Circle, a share type 7 is added to the oc_share table. Separate from the share with the circle, a public link token is also added. This token is now directly accessible to everyone without any form of security, but is necessary for the underlying circle token.

This patch omits the setToken, but it is still required behind the scenes for those receiving the share via the Circle.

Currently, public links rely entirely on the oc_share token entry. With my recently (extra) pushed patch, a change has been added to the getShareByToken function in the circle app, ensuring that a circles-token lookup also takes place in oc_circles_token and is not dependent on oc_share.token. The oc_share.token can then remain empty or be assigned a non-routable value.

Could you check whether this solves the problem for you as well?

Thanks, Tom

Comment thread lib/ShareByCircleProvider.php Outdated
Comment thread lib/ShareByCircleProvider.php Outdated
Comment on lines +591 to +595
$shareWrapper = $this->shareWrapperService->getShareByCirclesToken($token);
} catch (ShareWrapperNotFoundException $e2) {
throw new ShareNotFound(
'Share not found for token (tried both oc_share and oc_circles_token): ' . $token
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a duplicate of the fallback in getShareByToken, no?

Comment thread lib/Service/ShareWrapperService.php Outdated
Comment on lines +156 to +158
// Fallback: search using oc_circles_token.token
// This is necessary when oc_share.token is empty or does not match,
// but the circles token does exist.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that is true, I think getShareByToken will match the circle token, meaning that the fallback is useless.

Comment thread lib/ShareByCircleProvider.php Outdated
Comment on lines +605 to +607
if ($shareWrapper->getToken() === '' || $shareWrapper->getToken() === null) {
$shareWrapper->setToken($token);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should simply return the oc_circles_token.token in ShareWrapper->getToken() instead of the oc_share.token?

Comment thread lib/ShareByCircleProvider.php
… share by its circles token. Also set the circles token on the IShare object correct based on circles output.
@T0mWz
Copy link
Copy Markdown
Author

T0mWz commented Apr 23, 2026

Thanks for your feedback @artonge !

What I tested:
I’ve made a few improvements and also double-checked that it works with:

  1. A default oc_share.token which is used for public link shares
  2. A circles_token (rather than a public link token)
  3. An invalid token that doesn’t match either an oc_share.token or a circles_token

What changed:

  • ShareWrapperRequest: add getShareByCirclesToken() which joins oc_circles_token to find a share by its circles token
  • ShareWrapperService: add fallback to getShareByCirclesToken() when getShareByToken() throws ShareWrapperNotFoundException
  • ShareByCircleProvider: set the circles token on the IShare object after construction if oc_share.token is empty

Summary of this change:
When sharing with a Nextcloud Circle that includes external members, a public link token is stored in oc_share.token alongside the actual circles token in oc_circles_token.token. This public link is accessible to anyone without authentication, which is undesirable.

To prevent unauthenticated access, oc_share.token can be left empty.

This change adds a fallback in ShareWrapperService::getShareByToken() that looks up the share via oc_circles_token.token when no match is found in oc_share.token. After the IShare object is constructed from the database, the circles token is applied to it directly, ensuring the router always receives a valid non-empty token.

… share by its circles token. Also set the circles token on the IShare object correct based on circles output.
@cristianscheid
Copy link
Copy Markdown
Contributor

The issue this PR aimed to address should now be resolved by this other PR: #2454. Shall we go ahead and close this one?

@github-actions
Copy link
Copy Markdown
Contributor

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants