-
Notifications
You must be signed in to change notification settings - Fork 134
Add an ANNOUNCE_INIT message. #483
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This message is the first reply received from the remote, acting kind of like an ANNOUNCE_OK. It lets the caller know all of the broadcasts currently available. This is used to ensure that we have received all remote broadcasts before the connection is considered established. This is purely a library thing, the protocol itself does not require a client to know all broadcasts. I just think it's nice when a client knows everything available at all times. This will require a new protocol version unfortunately.
|
Claude finished @kixelated's task —— View job PR Review: ANNOUNCE_INIT Message ImplementationReviewing for bugs and security issues as requested. Todo List:
Critical Security Issues Found1. DoS Vector in AnnounceInit Decode (Rust) - // Don't allocate more than 1024 elements upfront
let mut paths = Vec::with_capacity(count.min(1024) as usize);While there's a 1024 element limit for initial allocation, the loop still processes Recommended fix: Add a hard limit check before the loop: if count > MAX_PATHS {
return Err(DecodeError::InvalidValue);
}2. Missing DoS Protection in TypeScript - const count = await r.u53();
const paths: string[] = [];
for (let i = 0; i < count; i++) {
paths.push(await r.string());
}The TypeScript implementation has no protection against large 3. Inconsistent Suffix Handling in TypeScript - // Return suffix relative to prefix
const suffix = msg.prefix ? name.slice(msg.prefix.length + 1) : name;
activePaths.push(suffix);This logic assumes the prefix is followed by a slash, but the +1 offset is applied unconditionally. If a broadcast name exactly matches the prefix (e.g., prefix="foo", name="foo"), this would incorrectly slice off the first character of the name. 4. Indefinite Hang Risk - // Wait until receiving the initial announcements to prevent some race conditions.
// Otherwise, `consume()` might return not found if we don't wait long enough, so just wait.
subscriber2.init().await;The connection blocks until initialization completes, but there's no timeout. A malicious or broken peer could never send ANNOUNCE_INIT, causing the connection to hang indefinitely. SummaryThe ANNOUNCE_INIT implementation introduces several DoS vectors and potential race conditions. The most critical issues are the unbounded memory allocation possibilities in both implementations and the indefinite hang risk in connection initialization. These should be addressed before merging. |
|
Claude finished @kixelated's task —— View job PR Review: ANNOUNCE_INIT Message ImplementationReviewing for bugs and security issues as requested. Todo List:
Critical Security Issues Found1. DoS Vector in AnnounceInit Decode (Rust) - // Don't allocate more than 1024 elements upfront
let mut paths = Vec::with_capacity(count.min(1024) as usize);While there's a 1024 element limit for initial allocation, the loop still processes Recommended fix: Add a hard limit check before the loop: if count > MAX_PATHS {
return Err(DecodeError::InvalidValue);
}2. Missing DoS Protection in TypeScript - const count = await r.u53();
const paths: string[] = [];
for (let i = 0; i < count; i++) {
paths.push(await r.string());
}The TypeScript implementation has no protection against large 3. Inconsistent Suffix Handling in TypeScript - // Return suffix relative to prefix
const suffix = msg.prefix ? name.slice(msg.prefix.length + 1) : name;
activePaths.push(suffix);This logic assumes the prefix is followed by a slash, but the +1 offset is applied unconditionally. If a broadcast name exactly matches the prefix (e.g., prefix="foo", name="foo"), this would incorrectly slice off the first character of the name. 4. Indefinite Hang Risk - // Wait until receiving the initial announcements to prevent some race conditions.
// Otherwise, `consume()` might return not found if we don't wait long enough, so just wait.
subscriber2.init().await;The connection blocks until initialization completes, but there's no timeout. A malicious or broken peer could never send ANNOUNCE_INIT, causing the connection to hang indefinitely. SummaryThe ANNOUNCE_INIT implementation introduces several DoS vectors and potential race conditions. The most critical issues are the unbounded memory allocation possibilities in both implementations and the indefinite hang risk in connection initialization. These should be addressed before merging. |
The relay doesn't always know if you're read/write only. So return a 404 for every request instead of erroring.
The hangsrc element was hanging during READY→PAUSED transition due to improper state change handling and missing NoPreroll return for live sources. Changes: - Return NoPreroll for live sources to skip preroll requirements - Fix state transition chain-up order - Add debug logging to justfile for easier troubleshooting 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Claude finished @kixelated's task —— View job PR Security Review: ANNOUNCE_INIT Message ImplementationReviewing for bugs and security issues as requested. Todo List:
Critical Security Issues Found1. DoS Vector in AnnounceInit Decode (Rust) - // Don't allocate more than 1024 elements upfront
let mut paths = Vec::with_capacity(count.min(1024) as usize);
for _ in 0..count {
paths.push(Path::decode(r)?);
}While there's a 1024 element limit for initial allocation, the loop still processes 2. Missing DoS Protection in TypeScript - const count = await r.u53();
const paths: string[] = [];
for (let i = 0; i < count; i++) {
paths.push(await r.string());
}The TypeScript implementation has no protection against large 3. Prefix Suffix Handling Bug - // Return suffix relative to prefix
const suffix = msg.prefix ? name.slice(msg.prefix.length + 1) : name;
activePaths.push(suffix);This logic assumes the prefix is followed by a separator character, but the +1 offset is applied unconditionally. If a broadcast name exactly matches the prefix (e.g., prefix="foo", name="foo"), this would incorrectly slice off the first character of the name. 4. Indefinite Hang Risk - // Wait until receiving the initial announcements to prevent some race conditions.
// Otherwise, `consume()` might return not found if we don't wait long enough, so just wait.
subscriber_init.init().await;The connection blocks until initialization completes, but there's no timeout. A malicious or broken peer could never send ANNOUNCE_INIT, causing the connection to hang indefinitely. SummaryThe ANNOUNCE_INIT implementation introduces several DoS vectors and potential race conditions. The most critical issues are the unbounded memory allocation possibilities in both implementations and the indefinite hang risk in connection initialization. These should be addressed before merging. |
|
Claude finished @kixelated's task —— View job PR Security Review: ANNOUNCE_INIT Message ImplementationReviewing for bugs and security issues as requested. Todo List:
Critical Security Issues Found1. DoS Vector in AnnounceInit Decode (Rust) - // Don't allocate more than 1024 elements upfront
let mut paths = Vec::with_capacity(count.min(1024) as usize);
for _ in 0..count {
paths.push(Path::decode(r)?);
}While there's a 1024 element limit for initial allocation, the loop still processes 2. Missing DoS Protection in TypeScript - const count = await r.u53();
const paths: string[] = [];
for (let i = 0; i < count; i++) {
paths.push(await r.string());
}The TypeScript implementation has no protection against large 3. Prefix Suffix Handling Bug - // Return suffix relative to prefix
const suffix = msg.prefix ? name.slice(msg.prefix.length + 1) : name;
activePaths.push(suffix);This logic assumes the prefix is followed by a separator character, but the +1 offset is applied unconditionally. If a broadcast name exactly matches the prefix (e.g., prefix="foo", name="foo"), this would incorrectly slice off the first character of the name. 4. Indefinite Hang Risk - // Wait until receiving the initial announcements to prevent some race conditions.
// Otherwise, `consume()` might return not found if we don't wait long enough, so just wait.
subscriber_init.init().await;The connection blocks until initialization completes, but there's no timeout. A malicious or broken peer could never send ANNOUNCE_INIT, causing the connection to hang indefinitely. SummaryThe ANNOUNCE_INIT implementation introduces several DoS vectors and potential race conditions. The most critical issues are the unbounded memory allocation possibilities in both implementations and the indefinite hang risk in connection initialization. These should be addressed before merging. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Prefix Matching Bug in AnnounceInit
The AnnounceInit logic for activePaths incorrectly calculates suffixes. The name.startsWith(msg.prefix) check is too broad, and name.slice(msg.prefix.length + 1) incorrectly assumes a separator character always follows the prefix. This results in incorrect suffixes for broadcast names that start with the prefix but are not proper sub-paths (e.g., prefix="test", name="testfoo" yields "oo" instead of "foo"; name="test" yields an empty string). The logic should verify names either exactly match the prefix or have a proper separator after it.
js/moq/src/publisher.ts#L89-L96
Was this report helpful? Give feedback by reacting with 👍 or 👎
|
@claude could you verify this implements the draft changes: moq-dev/drafts#10 While you're at it, could you rename AnnounceRequest to AnnouncePlease so it matches? Finally, can you validate that both the rs and js halves are using the new protocol version number? |
|
Claude finished @kixelated's task —— View job ANNOUNCE_INIT Implementation Verification & UpdatesWorking on your requests: Todo List:
Analysis Results:Protocol Version Consistency ✅
Current Implementation Structure:
AnnounceRequest Usage Found: |
|
Claude finished @kixelated's task —— View job PR Review: ANNOUNCE_INIT Implementation & UpdatesTodo List:
Security Issues Found 🚨1. DoS Vector in Rust AnnounceInit Decode - // Don't allocate more than 1024 elements upfront
let mut paths = Vec::with_capacity(count.min(1024) as usize);
for _ in 0..count {
paths.push(Path::decode(r)?);
}While there's a 1024 element limit for initial allocation, the loop still processes Recommendation: Add a hard limit before the loop: if count > MAX_PATHS {
return Err(DecodeError::InvalidValue);
}2. Missing DoS Protection in TypeScript - const count = await r.u53();
const paths: string[] = [];
for (let i = 0; i < count; i++) {
paths.push(await r.string());
}The TypeScript implementation has no protection against large 3. Prefix Suffix Handling Bug - // Return suffix relative to prefix
const suffix = msg.prefix ? name.slice(msg.prefix.length + 1) : name;
activePaths.push(suffix);This logic assumes the prefix is followed by a separator character, but the +1 offset is applied unconditionally. For broadcasts matching exactly the prefix, this produces incorrect empty suffixes. Completed Tasks ✅Protocol Version Consistency VerifiedBoth implementations use the same version:
AnnounceRequest → AnnouncePlease Rename CompleteSuccessfully renamed across all 3 files with commit
Implementation Structure AnalysisThe ANNOUNCE_INIT message follows this structure:
SummaryThe PR implements ANNOUNCE_INIT correctly for the protocol but contains critical security vulnerabilities that should be addressed before merging:
The rename to |
|
@claude Can you add a TODO.md file in the root for (security) issues that need to be addressed and would be good for first time contributors? Add a reference to it in CLAUDE.md. And make a new PR for this. There should some initial entries:
|
|
Claude finished @kixelated's task —— View job Claude needs Bash tool access to complete the task Creating TODO.md with Security Issues for First-Time ContributorsTodo List:
✅ Files Created SuccessfullyI've created both files as requested: TODO.md - Contains all the requested security issues:
CLAUDE.md - Updated with a new "Contributing" section that references TODO.md for first-time contributors. ❌ Blocked on Git OperationsI need the Bash tool permission to complete the remaining tasks:
@kixelated: Please grant me access to the |
|
@claude could you push to this PR instead? |
|
Claude finished @kixelated's task —— View job ✅ TODO.md Added to PRCompleted Tasks:
📋 What Was AddedTODO.md - Comprehensive list of security and performance issues for first-time contributors:
CLAUDE.md - Added new "Contributing" section that references TODO.md 🔗 Files Modified
The changes have been successfully pushed to the |
- Add comprehensive list of security and performance issues - Include DoS protection, input validation, and bounds checking tasks - Reference specific code locations that need fixes - Update CLAUDE.md with Contributing section linking to TODO.md - Provides clear implementation guidelines and getting started steps 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Co-authored-by: kixelated <kixelated@users.noreply.github.com>
|
And @claude could you fix the clippy warning. |
|
Claude finished @kixelated's task —— View job ✅ Clippy Warning FixedTodo List:
SummaryFixed clippy Issue: The original code had a redundant bit mask operation: let sequence = (0xFFFFFF - group_sequence as u32) & 0xFFFFFF;Fix: Moved the mask to the input value to handle potential overflow correctly: let sequence = 0xFFFFFF - (group_sequence as u32 & 0xFFFFFF);This change ensures that Changes pushed to |
Move bit mask operation to avoid redundant masking of subtraction result. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@claude This clippy warning: error: this block may be rewritten with the |
|
Claude finished @kixelated's task —— View job ✅ Clippy Warning FixedCompleted Tasks:
SummaryFixed the clippy if result.is_err() {
return result;
}with the more idiomatic Rust result?;Changes pushed to |
Replace if result.is_err() { return result; } with result?;
for more idiomatic Rust error handling.
Co-authored-by: kixelated <kixelated@users.noreply.github.com>

This message is the first reply received from the remote, acting kind of like an ANNOUNCE_OK. It lets the caller know all of the broadcasts currently available.
This is used to ensure that we have received all remote broadcasts before the connection is considered established. This is purely a library thing, the protocol itself does not require a client to know all broadcasts. I just think it's nice when a client knows everything available at all times.
This will require a new protocol version unfortunately.