Skip to content

Sentinel Audit: Broken Auth in WebSocket Endpoint#157

Open
Vaiditya2207 wants to merge 1 commit intomainfrom
sentinel-audit-websocket-auth-9346302758074673113
Open

Sentinel Audit: Broken Auth in WebSocket Endpoint#157
Vaiditya2207 wants to merge 1 commit intomainfrom
sentinel-audit-websocket-auth-9346302758074673113

Conversation

@Vaiditya2207
Copy link
Copy Markdown
Owner

@Vaiditya2207 Vaiditya2207 commented Mar 15, 2026

Sentinel has identified a significant security vulnerability in the codebase. The /ws/stream WebSocket endpoint in the Rust syscore backend allows unauthenticated clients to subscribe to and stream live execution logs and memory traces for any container by simply providing a job_id.

The findings have been professionally documented in SECURITY_ISSUE.md with severity, impact, reproduction steps, and remediation advice. Additionally, the architectural learnings have been recorded in the .jules/sentinel.md journal.

No actual code changes were made, adhering to the strict auditing boundary rules. All tests pass successfully.


PR created automatically by Jules for task 9346302758074673113 started by @Vaiditya2207

Summary by CodeRabbit

  • Documentation
    • Added new security vulnerability documentation for an unauthenticated WebSocket endpoint, including vulnerability details and remediation guidance.
    • Updated existing security issue documentation with revised vulnerability assessment and recommendations.

- Found and documented CRITICAL Broken Auth vulnerability in `syscore/src/server/websocket.rs`.
- The `/ws/stream` endpoint lacks authentication, allowing anyone to subscribe to arbitrary job logs.
- Wrote findings to `SECURITY_ISSUE.md` using the exact requested template.
- Appended vulnerability pattern to `.jules/sentinel.md` journal.
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
okernel Ready Ready Preview, Comment Mar 15, 2026 10:03pm

@github-actions github-actions Bot added documentation Improvements or additions to documentation source test ci labels Mar 15, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 15, 2026

📝 Walkthrough

Walkthrough

Updated security documentation to add a new unauthenticated WebSocket endpoint vulnerability pattern and replace an existing arbitrary file write vulnerability description with a WebSocket authentication issue, including reproduction steps and remediation guidance.

Changes

Cohort / File(s) Summary
Security Documentation
.jules/sentinel.md, SECURITY_ISSUE.md
Added new WebSocket endpoint vulnerability pattern with vulnerability description, systemic cause, and auditor recommendations. Replaced file write vulnerability narrative with unauthenticated WebSocket endpoint vulnerability, including updated code context, reproduction steps, remediation guidance, and security references.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A rabbit hops through docs so grand,
Finding WebSockets unplanned,
Auth and tokens we now demand,
Security fortified hand in hand,
Our burrow now safely will stand! 🔐

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: documenting a broken authentication vulnerability in a WebSocket endpoint, which aligns with the security audit findings and file modifications in SECURITY_ISSUE.md.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sentinel-audit-websocket-auth-9346302758074673113
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
.jules/sentinel.md (1)

8-8: Tighten protocol wording to avoid a misleading claim.

Line 8 currently implies WebSocket handshakes lack standard HTTP headers, which is not accurate. The key limitation is that browser WebSocket APIs do not let client JS set arbitrary custom headers. Please rephrase to avoid confusion in future security guidance.

Proposed wording update
-Systemic Cause: WebSockets are inherently stateful and lack standard HTTP headers during the handshake in browser APIs. Developers often forget or skip implementing a custom authentication flow (e.g., ticket-based auth via query params or an initial auth payload) for WebSocket connections, leaving sensitive real-time data exposed to anyone who knows the subscription topic or ID.
+Systemic Cause: WebSockets are inherently stateful, and while the handshake is HTTP-based, browser WebSocket APIs do not allow setting arbitrary custom headers from client JavaScript. Developers often forget or skip implementing an explicit authentication and authorization flow (e.g., short-lived signed ticket, session/cookie validation, or initial auth message), leaving sensitive real-time data exposed to anyone who knows the subscription topic or ID.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.jules/sentinel.md at line 8, The sentence in the "Systemic Cause" paragraph
that states "WebSockets are inherently stateful and lack standard HTTP headers
during the handshake" is misleading; change the wording to say that while
WebSocket handshakes use HTTP, browser WebSocket APIs do not allow client-side
JavaScript to set arbitrary custom headers, so developers must implement
explicit auth flows (e.g., ticket-based query params or initial auth payloads)
to avoid exposing subscriptions; update the line in .jules/sentinel.md (the
"Systemic Cause" paragraph) to this corrected phrasing.
SECURITY_ISSUE.md (2)

23-28: Clarify that the vulnerability allows accessing other users' jobs.

The reproduction steps currently describe submitting your own execution request to obtain a job_id. While this works for testing, it doesn't fully illustrate the attack scenario where an attacker accesses another user's job data. Consider adding a note that the real vulnerability is the ability to subscribe to any user's job_id, not just your own.

💡 Suggested clarification
 🛠️ Steps to Reproduce
 1. Start the `syscore` backend service.
-2. Submit a valid code execution request to `/api/execute` to generate a valid `job_id` and start a container.
+2. Submit a valid code execution request to `/api/execute` to generate a valid `job_id` and start a container. (Note: In a real attack, the attacker would obtain another user's `job_id` through enumeration, leaks, or side channels.)
 3. Using a generic WebSocket client (e.g., `wscat` or a browser console), connect to `ws://localhost:3001/ws/stream` without any authentication headers or tokens.
 4. Send the message `subscribe:<job_id>` using the valid `job_id` obtained in step 2.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SECURITY_ISSUE.md` around lines 23 - 28, The reproduction steps miss that an
attacker can subscribe to other users' jobs; update the WebSocket subscription
handling to enforce authentication and job-ownership checks: in the WebSocket
route handler that processes messages for "/ws/stream" (the connection/subscribe
logic) call the authentication middleware and add a verifyJobOwnership(job_id,
user) check before allowing a "subscribe:<job_id>" request to start streaming;
if ownership fails, reject the subscription and close the connection or send an
authorization error. Ensure the check uses the same job lookups used by
execute/submit logic so only the owner (or an authorized role) can subscribe.

30-33: Consider specifying preferred authentication approach.

The remediation mentions multiple valid approaches (token in handshake vs. first-message authentication) without indicating which is preferred. For developers implementing the fix, providing a recommendation would be helpful.

Additionally, consider emphasizing that both authentication (who is the user) and authorization (does this user own this job_id) are required.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SECURITY_ISSUE.md` around lines 30 - 33, Prefer a single, concrete approach:
require the client to send an authentication payload containing a JWT as the
very first WebSocket message (rather than relying on query params) and reject
any connection that does not authenticate within a short timeout; upon receiving
the token, validate it (verify signature/expiry) and then perform authorization
by checking ownership of the requested job_id via ContainerManager (or the job
state store) so only the job owner can access that job_id, and ensure all code
paths in the WebSocket handler (handshake/auth flow, message handlers, and
connection accept/reject logic) enforce this constraint and log failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@SECURITY_ISSUE.md`:
- Line 21: The impact sentence is too long and speculative; replace it with two
clear sentences stating that the WebSocket endpoint allows unauthenticated
connections which can subscribe to any active job_id, and that possessing a
valid job_id (via leak or predictability) lets an attacker stream sensitive
execution logs, source snippets, and memory contents; remove the parenthetical
and the UUIDv4 brute-force speculation and rewrite the statement to focus on the
unauthenticated exposure of data via the WebSocket endpoint and the sensitive
artifacts (logs, trace events, memory) accessible given a valid job_id.

---

Nitpick comments:
In @.jules/sentinel.md:
- Line 8: The sentence in the "Systemic Cause" paragraph that states "WebSockets
are inherently stateful and lack standard HTTP headers during the handshake" is
misleading; change the wording to say that while WebSocket handshakes use HTTP,
browser WebSocket APIs do not allow client-side JavaScript to set arbitrary
custom headers, so developers must implement explicit auth flows (e.g.,
ticket-based query params or initial auth payloads) to avoid exposing
subscriptions; update the line in .jules/sentinel.md (the "Systemic Cause"
paragraph) to this corrected phrasing.

In `@SECURITY_ISSUE.md`:
- Around line 23-28: The reproduction steps miss that an attacker can subscribe
to other users' jobs; update the WebSocket subscription handling to enforce
authentication and job-ownership checks: in the WebSocket route handler that
processes messages for "/ws/stream" (the connection/subscribe logic) call the
authentication middleware and add a verifyJobOwnership(job_id, user) check
before allowing a "subscribe:<job_id>" request to start streaming; if ownership
fails, reject the subscription and close the connection or send an authorization
error. Ensure the check uses the same job lookups used by execute/submit logic
so only the owner (or an authorized role) can subscribe.
- Around line 30-33: Prefer a single, concrete approach: require the client to
send an authentication payload containing a JWT as the very first WebSocket
message (rather than relying on query params) and reject any connection that
does not authenticate within a short timeout; upon receiving the token, validate
it (verify signature/expiry) and then perform authorization by checking
ownership of the requested job_id via ContainerManager (or the job state store)
so only the job owner can access that job_id, and ensure all code paths in the
WebSocket handler (handshake/auth flow, message handlers, and connection
accept/reject logic) enforce this constraint and log failures.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a42e5f7e-15b8-4f4e-8bf5-67a7b3e60ca2

📥 Commits

Reviewing files that changed from the base of the PR and between 1b3df34 and 8f77c11.

📒 Files selected for processing (2)
  • .jules/sentinel.md
  • SECURITY_ISSUE.md

Comment thread SECURITY_ISSUE.md

🎯 Potential Impact
An authenticated attacker (even using the weak default `AETHER_UPLOAD_KEY` of "update_me_please") can overwrite arbitrary files on the system with the permissions of the user running the `syscore` backend service. This can lead to Remote Code Execution (RCE) by overwriting `.ssh/authorized_keys`, cron jobs, or system binaries, leading to complete system compromise.
An unauthenticated attacker can connect to the WebSocket endpoint and subscribe to any active `job_id`. Since job IDs might be predictable or leaked (or the attacker could simply brute-force active UUIDs if they have enough throughput, though UUIDv4 makes this harder, the endpoint still exposes data without auth). If an attacker obtains a valid `job_id`, they can stream sensitive execution logs, source code snippets (via trace events), and memory contents of other users' executing code, leading to severe Data Leakage and privacy violations.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Simplify the impact statement for clarity.

The sentence is overly long with nested parentheticals that reduce readability. The discussion of UUIDv4 brute-forcing, while technically accurate, dilutes the main point: the endpoint lacks authentication and exposes sensitive data when valid job_ids are known.

Consider splitting this into clearer statements or removing the speculative brute-force discussion.

📝 Suggested simplification
-An unauthenticated attacker can connect to the WebSocket endpoint and subscribe to any active `job_id`. Since job IDs might be predictable or leaked (or the attacker could simply brute-force active UUIDs if they have enough throughput, though UUIDv4 makes this harder, the endpoint still exposes data without auth). If an attacker obtains a valid `job_id`, they can stream sensitive execution logs, source code snippets (via trace events), and memory contents of other users' executing code, leading to severe Data Leakage and privacy violations.
+An unauthenticated attacker can connect to the WebSocket endpoint and subscribe to any active `job_id`. If an attacker obtains a valid `job_id` (through predictability, leakage, or other means), they can stream sensitive execution logs, source code snippets (via trace events), and memory contents of other users' executing code, leading to severe data leakage and privacy violations.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
An unauthenticated attacker can connect to the WebSocket endpoint and subscribe to any active `job_id`. Since job IDs might be predictable or leaked (or the attacker could simply brute-force active UUIDs if they have enough throughput, though UUIDv4 makes this harder, the endpoint still exposes data without auth). If an attacker obtains a valid `job_id`, they can stream sensitive execution logs, source code snippets (via trace events), and memory contents of other users' executing code, leading to severe Data Leakage and privacy violations.
An unauthenticated attacker can connect to the WebSocket endpoint and subscribe to any active `job_id`. If an attacker obtains a valid `job_id` (through predictability, leakage, or other means), they can stream sensitive execution logs, source code snippets (via trace events), and memory contents of other users' executing code, leading to severe data leakage and privacy violations.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SECURITY_ISSUE.md` at line 21, The impact sentence is too long and
speculative; replace it with two clear sentences stating that the WebSocket
endpoint allows unauthenticated connections which can subscribe to any active
job_id, and that possessing a valid job_id (via leak or predictability) lets an
attacker stream sensitive execution logs, source snippets, and memory contents;
remove the parenthetical and the UUIDv4 brute-force speculation and rewrite the
statement to focus on the unauthenticated exposure of data via the WebSocket
endpoint and the sensitive artifacts (logs, trace events, memory) accessible
given a valid job_id.

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

Labels

ci documentation Improvements or additions to documentation source test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant