Skip to content

Commit c682c96

Browse files
committed
Merge pull request #255 from dodok8/dodok8-fix-issue-247
Fix direct message visibility filtering in status queries
2 parents fba9f48 + 1fdbda7 commit c682c96

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

CHANGES.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ Version 0.6.14
66

77
To be released.
88

9+
- Fixed a critical security vulnerability where direct messages (DMs) were
10+
visible to all authenticated users regardless of whether they were
11+
participants in the conversation. The visibility filter now correctly
12+
restricts direct messages to only the sender and mentioned recipients,
13+
preventing unauthorized access to private conversations.
14+
[[#247], [#255] by Hyeonseo Kim]
15+
16+
[#247]: https://github.com/fedify-dev/hollo/issues/247
17+
[#255]: https://github.com/fedify-dev/hollo/pull/255
18+
919

1020
Version 0.6.13
1121
--------------
@@ -957,3 +967,5 @@ Version 0.1.0
957967
-------------
958968

959969
Released on October 22, 2024. Initial release.
970+
971+
<!-- cSpell: ignore Hyeonseo -->

src/api/v1/statuses.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,18 @@ const app = new Hono<{ Variables: Variables }>();
8080
/**
8181
* Builds visibility conditions for post queries based on viewer's permissions.
8282
* For unauthenticated users, only public/unlisted posts are visible.
83-
* For authenticated users, includes private posts from accounts they follow.
83+
* For authenticated users, includes private posts from accounts they follow,
84+
* and direct posts where they are mentioned or are the author.
8485
*/
8586
function buildVisibilityConditions(viewerAccountId: Uuid | null | undefined) {
8687
if (viewerAccountId == null) {
8788
// Unauthenticated: only public and unlisted posts
8889
return inArray(posts.visibility, ["public", "unlisted"]);
8990
}
9091

91-
// Authenticated: include private posts based on follower relationships
92+
// Authenticated: include private and direct posts based on relationships
9293
return or(
93-
inArray(posts.visibility, ["public", "unlisted", "direct"]),
94+
inArray(posts.visibility, ["public", "unlisted"]),
9495
and(
9596
eq(posts.visibility, "private"),
9697
or(
@@ -111,12 +112,24 @@ function buildVisibilityConditions(viewerAccountId: Uuid | null | undefined) {
111112
),
112113
),
113114
),
114-
// Also include posts that mention the viewer
115-
exists(
116-
db
117-
.select({ id: mentions.postId })
118-
.from(mentions)
119-
.where(eq(mentions.accountId, viewerAccountId)),
115+
and(
116+
inArray(posts.visibility, ["private", "direct"]),
117+
or(
118+
// User's own direct posts
119+
eq(posts.accountId, viewerAccountId),
120+
// Direct posts where the user is mentioned
121+
exists(
122+
db
123+
.select({ postId: mentions.postId })
124+
.from(mentions)
125+
.where(
126+
and(
127+
eq(mentions.postId, posts.id),
128+
eq(mentions.accountId, viewerAccountId),
129+
),
130+
),
131+
),
132+
),
120133
),
121134
);
122135
}

0 commit comments

Comments
 (0)