Skip to content

Commit 07f565c

Browse files
authored
Merge branch 'master' into cursor/await-mode-change-restart
2 parents ed5c1aa + 055728e commit 07f565c

8 files changed

Lines changed: 246 additions & 10 deletions

File tree

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
blank_issues_enabled: true
2+
contact_links:
3+
- name: 🔒 Report a Critical Security Vulnerability (Private)
4+
url: https://github.com/ap0ught/matrix/security/advisories/new
5+
about: For sensitive or critical vulnerabilities, please use GitHub's private Security Advisory system instead of a public issue.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: 🔒 Security Vulnerability Report
2+
description: Report a security vulnerability or weakness in Matrix Digital Rain. For sensitive disclosures, please use GitHub Security Advisories instead.
3+
title: "[Security]: "
4+
labels: ["security", "vulnerability"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
## ⚠️ Important: Responsible Disclosure
10+
11+
**For sensitive or critical vulnerabilities, please do NOT use this public issue form.**
12+
Instead, use the [**GitHub Security Advisory**](https://github.com/ap0ught/matrix/security/advisories/new) (private disclosure).
13+
14+
This template is for:
15+
- Low-severity security concerns or hardening suggestions
16+
- Security-related questions or discussions
17+
- Issues that do not expose sensitive user data or allow remote exploitation
18+
19+
See our [Security Policy](https://github.com/ap0ught/matrix/blob/master/SECURITY.md) for full guidance.
20+
21+
- type: dropdown
22+
id: severity
23+
attributes:
24+
label: Severity
25+
description: How severe is this vulnerability?
26+
options:
27+
- High – exposes sensitive data or allows significant privilege escalation
28+
- Medium – limited impact, requires user interaction or specific conditions
29+
- Low – minor weakness, defense-in-depth improvement
30+
- Informational – security suggestion or best practice
31+
validations:
32+
required: true
33+
34+
- type: dropdown
35+
id: component
36+
attributes:
37+
label: Affected Component
38+
description: Which part of the application is affected?
39+
options:
40+
- Spotify OAuth / Authentication
41+
- URL parameter handling / Config parsing
42+
- WebGL / WebGPU renderer
43+
- Service Worker / PWA / Caching
44+
- GitHub Actions / CI workflows
45+
- Third-party dependencies (REGL, gl-matrix, etc.)
46+
- Other
47+
validations:
48+
required: true
49+
50+
- type: textarea
51+
id: description
52+
attributes:
53+
label: Vulnerability Description
54+
description: Describe the vulnerability clearly. Do NOT include proof-of-concept exploit code for critical issues — use Security Advisories for those.
55+
placeholder: |
56+
A clear and concise description of the security issue.
57+
What is the weakness? What could an attacker do with it?
58+
validations:
59+
required: true
60+
61+
- type: textarea
62+
id: steps
63+
attributes:
64+
label: Steps to Reproduce
65+
description: How can someone reproduce this issue?
66+
placeholder: |
67+
1. Open the application at http://localhost:8000
68+
2. Navigate to ...
69+
3. Observe ...
70+
validations:
71+
required: true
72+
73+
- type: textarea
74+
id: impact
75+
attributes:
76+
label: Potential Impact
77+
description: What is the worst-case impact of this vulnerability if exploited?
78+
placeholder: |
79+
Describe the potential impact on users or the application.
80+
e.g. "An attacker could steal a user's Spotify access token by..."
81+
validations:
82+
required: true
83+
84+
- type: textarea
85+
id: suggested-fix
86+
attributes:
87+
label: Suggested Fix (optional)
88+
description: If you have a suggested fix or mitigation, please describe it here.
89+
placeholder: |
90+
e.g. "Validate the `state` parameter using a cryptographically random value..."
91+
92+
- type: textarea
93+
id: environment
94+
attributes:
95+
label: Environment
96+
description: Browser, OS, and application version where you observed this issue.
97+
placeholder: |
98+
- Browser: Chrome 120 / Firefox 121 / Safari 17
99+
- OS: macOS 14 / Windows 11 / Ubuntu 22.04
100+
- Renderer: WebGL / WebGPU
101+
- Version: (see VERSION file or URL, e.g. 1.0.0)
102+
103+
- type: checkboxes
104+
id: checklist
105+
attributes:
106+
label: Checklist
107+
options:
108+
- label: I have read the [Security Policy](https://github.com/ap0ught/matrix/blob/master/SECURITY.md)
109+
required: true
110+
- label: This is NOT a sensitive/critical vulnerability (those should be reported via [GitHub Security Advisories](https://github.com/ap0ught/matrix/security/advisories/new))
111+
required: true
112+
- label: I have searched existing issues to avoid duplicates
113+
required: true

.github/dependabot.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
version: 2
2+
updates:
3+
# Keep npm dependencies up to date
4+
- package-ecosystem: "npm"
5+
directory: "/"
6+
schedule:
7+
interval: "weekly"
8+
open-pull-requests-limit: 10
9+
labels:
10+
- "dependencies"
11+
- "security"
12+
13+
# Keep GitHub Actions up to date
14+
- package-ecosystem: "github-actions"
15+
directory: "/"
16+
schedule:
17+
interval: "weekly"
18+
open-pull-requests-limit: 10
19+
labels:
20+
- "dependencies"
21+
- "security"

.github/workflows/master-branch-protection.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
node-version: '18'
2525

2626
- name: Setup Python
27-
uses: actions/setup-python@v4
27+
uses: actions/setup-python@v5
2828
with:
2929
python-version: '3.11'
3030

@@ -158,15 +158,15 @@ jobs:
158158
uses: actions/checkout@v4
159159

160160
- name: Run Trivy vulnerability scanner
161-
uses: aquasecurity/trivy-action@master
161+
uses: aquasecurity/trivy-action@v0.35.0
162162
with:
163163
scan-type: 'fs'
164164
scan-ref: '.'
165165
format: 'sarif'
166166
output: 'trivy-results.sarif'
167167

168168
- name: Upload Trivy scan results to GitHub Security tab
169-
uses: github/codeql-action/upload-sarif@v2
169+
uses: github/codeql-action/upload-sarif@v3
170170
if: always()
171171
with:
172172
sarif_file: 'trivy-results.sarif'

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ jobs:
140140
ls -lh "matrix-${{ steps.version.outputs.version }}.zip"
141141
142142
- name: Create GitHub Release
143-
uses: softprops/action-gh-release@v1
143+
uses: softprops/action-gh-release@v2
144144
with:
145145
tag_name: ${{ steps.version.outputs.tag }}
146146
name: Matrix Digital Rain v${{ steps.version.outputs.version }}

SECURITY.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Security Policy
2+
3+
## Supported Versions
4+
5+
| Version | Supported |
6+
| ------- | ------------------ |
7+
| latest | :white_check_mark: |
8+
9+
## Reporting a Vulnerability
10+
11+
If you discover a security vulnerability in the Matrix Digital Rain project, please report it responsibly.
12+
13+
**Please do not open a public GitHub issue for security vulnerabilities.**
14+
15+
Instead, please report security vulnerabilities by:
16+
17+
1. Opening a [GitHub Security Advisory](https://github.com/ap0ught/matrix/security/advisories/new) (preferred)
18+
2. Or emailing the repository maintainer directly
19+
20+
Please include the following information in your report:
21+
22+
- A description of the vulnerability and its potential impact
23+
- Steps to reproduce the issue
24+
- Any proof-of-concept code (if applicable)
25+
- Suggested fix (if you have one)
26+
27+
## Security Considerations
28+
29+
### Client-Side Application
30+
31+
Matrix Digital Rain is a purely client-side web application with no server-side components. This means:
32+
33+
- No user data is transmitted to any server (except optional Spotify API integration)
34+
- No authentication is required to use the application
35+
- All processing happens in the browser
36+
37+
### Spotify Integration
38+
39+
The optional Spotify integration uses the OAuth 2.0 Authorization Code flow:
40+
41+
- Access tokens are stored in `localStorage` for persistence between sessions
42+
- The OAuth `state` parameter uses a cryptographically random value (via `crypto.getRandomValues`) to prevent CSRF attacks
43+
- No client secrets are stored in the codebase - the Spotify client ID is provided by the user
44+
45+
### Content Security
46+
47+
- The application uses WebGL/WebGPU for rendering, which is sandboxed by the browser
48+
- No user-provided content is rendered as HTML without sanitization
49+
- URL parameters are validated and parsed through a typed configuration system
50+
51+
## Dependencies
52+
53+
This project uses the following dependencies:
54+
55+
| Dependency | Purpose | Location | GitHub | Activity |
56+
|---|---|---|---|---|
57+
| **REGL** | WebGL wrapper for rendering | Bundled locally in `/lib/` | [regl-project/regl](https://github.com/regl-project/regl) | Mature, widely used WebGL wrapper. Core feature development has largely stabilized, but it remains production-ready and receives occasional maintenance updates. |
58+
| **gl-matrix** | High-performance matrix and vector math | Bundled locally in `/lib/` | [toji/gl-matrix](https://github.com/toji/gl-matrix) | Actively maintained and widely adopted for WebGL/WebGPU math. Receives regular releases. The bundled version tracks a stable 3.x release of the library. |
59+
| **@playwright/test** | End-to-end browser testing (dev only) | npm `devDependency`**not included in production builds** | [microsoft/playwright](https://github.com/microsoft/playwright) | Very actively maintained by Microsoft with frequent releases and an extensive user base. This project pins a recent stable major version in its devDependencies. |
60+
61+
Dependencies are automatically monitored by [Dependabot](.github/dependabot.yml) for security updates.

js/spotify.js

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ export default class SpotifyIntegration {
3939
// Check if we're returning from OAuth redirect
4040
await this.handleOAuthCallback();
4141
}
42+
/**
43+
* Generate a cryptographically random state value for OAuth CSRF protection
44+
*/
45+
generateState() {
46+
if (!window.crypto || !window.crypto.getRandomValues) {
47+
throw new Error("Secure random generation not available - Spotify authentication requires a secure context (HTTPS or http://localhost)");
48+
}
49+
const array = new Uint8Array(16);
50+
crypto.getRandomValues(array);
51+
return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("");
52+
}
53+
4254
/**
4355
* Start the OAuth authentication flow
4456
*/
@@ -48,12 +60,22 @@ export default class SpotifyIntegration {
4860
return;
4961
}
5062

63+
// Generate and store a random state value to prevent CSRF attacks
64+
let state;
65+
try {
66+
state = this.generateState();
67+
} catch (e) {
68+
this.emit("error", e.message);
69+
return;
70+
}
71+
sessionStorage.setItem("spotify_oauth_state", state);
72+
5173
const authUrl = new URL("https://accounts.spotify.com/authorize");
5274
authUrl.searchParams.set("client_id", this.clientId);
5375
authUrl.searchParams.set("response_type", "code");
5476
authUrl.searchParams.set("redirect_uri", this.redirectUri);
5577
authUrl.searchParams.set("scope", this.scopes);
56-
authUrl.searchParams.set("state", "matrix-spotify-auth");
78+
authUrl.searchParams.set("state", state);
5779

5880
// Use direct redirect instead of popup for better compatibility
5981
window.location.href = authUrl.toString();
@@ -76,19 +98,33 @@ export default class SpotifyIntegration {
7698
return;
7799
}
78100

79-
if (code && state === "matrix-spotify-auth") {
101+
if (code && state) {
102+
// Clean up URL immediately to remove auth parameters from browser history
103+
window.history.replaceState({}, document.title, window.location.pathname);
104+
105+
// Verify state parameter to prevent CSRF attacks
106+
const expectedState = sessionStorage.getItem("spotify_oauth_state");
107+
sessionStorage.removeItem("spotify_oauth_state");
108+
109+
if (!expectedState || state !== expectedState) {
110+
this.emit("error", "Spotify OAuth state mismatch - possible CSRF attack");
111+
return;
112+
}
113+
80114
console.log("Processing Spotify OAuth callback with code:", code.substring(0, 20) + "...");
81115
const result = await this.exchangeCodeForTokens(code);
82116

83-
// Clean up URL
84-
window.history.replaceState({}, document.title, window.location.pathname);
85-
86117
if (result.error) {
87118
console.error("Token exchange error:", result.error);
88119
this.emit("error", "Failed to exchange code for tokens: " + result.error);
89120
} else {
90121
console.log("Spotify authentication successful");
91122
}
123+
} else if (code) {
124+
// Code present but state is missing — reject and clean up to avoid auth code leaking in URL
125+
window.history.replaceState({}, document.title, window.location.pathname);
126+
sessionStorage.removeItem("spotify_oauth_state");
127+
this.emit("error", "Spotify OAuth state parameter missing - possible CSRF attack");
92128
}
93129
}
94130
/**

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"devDependencies": {
3-
"@playwright/test": "^1.56.1"
3+
"@playwright/test": "^1.58.2"
44
}
55
}

0 commit comments

Comments
 (0)