Feature/workspaces api services - #31
philvarner-snyk wants to merge 9 commits into
Conversation
Introduce multi-workspace support with role-based access control, audit logging, webhook delivery, rule engine with scheduled execution, CSV todo import, and notes CRUD. Adds new Mongoose models (Workspace, WorkspaceMember, AuditEvent, Webhook, WebhookDelivery, Rule, Note), API middleware, and supporting documentation. Made-with: Cursor
⛔ Snyk checks have failed. 19 issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
| if (req.query.from) q.createdAt.$gte = new Date(req.query.from); | ||
| if (req.query.to) q.createdAt.$lte = new Date(req.query.to); | ||
| } | ||
| AuditEvent.countDocuments(q).exec(function (err, total) { |
There was a problem hiding this comment.
NoSQL Injection
Unsanitized input from an HTTP parameter flows into countDocuments, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.
Line 70 | CWE-943 | Priority score 821 | Learn more about this vulnerability
| } | ||
| var workspaceObjId = new mongoose.Types.ObjectId(workspaceId); | ||
| var qSafe = Object.assign({}, q, { workspace: workspaceObjId }); | ||
| Todo.countDocuments(qSafe).exec(function (err, total) { |
There was a problem hiding this comment.
NoSQL Injection
Unsanitized input from an HTTP parameter flows into countDocuments, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.
Line 105 | CWE-943 | Priority score 821 | Learn more about this vulnerability
Data flow: 12 steps
Step 1 - 7
nodejs-goof/routes/workspace-todos.js
Line 90 in 8eab186
Step 8 - 10 routes/workspace-todos.js#L104
Step 11 - 12
nodejs-goof/routes/workspace-todos.js
Line 105 in 8eab186
| } | ||
| AuditEvent.countDocuments(q).exec(function (err, total) { | ||
| if (err) return next(err); | ||
| AuditEvent.find(q) |
There was a problem hiding this comment.
NoSQL Injection
Unsanitized input from an HTTP parameter flows into find, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.
Line 72 | CWE-943 | Priority score 821 | Learn more about this vulnerability
| var qSafe = Object.assign({}, q, { workspace: workspaceObjId }); | ||
| Todo.countDocuments(qSafe).exec(function (err, total) { | ||
| if (err) return next(err); | ||
| Todo.find(qSafe) |
There was a problem hiding this comment.
NoSQL Injection
Unsanitized input from an HTTP parameter flows into find, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.
Line 107 | CWE-943 | Priority score 821 | Learn more about this vulnerability
Data flow: 12 steps
Step 1 - 7
nodejs-goof/routes/workspace-todos.js
Line 90 in 8eab186
Step 8 - 10 routes/workspace-todos.js#L104
Step 11 - 12
nodejs-goof/routes/workspace-todos.js
Line 107 in 8eab186
| details: { user: newUser, role: role }, | ||
| ip: req.ip, | ||
| }); | ||
| webhookDelivery.notifyWebhooks(workspaceId, 'member.added', { resourceId: String(member._id), data: { user: newUser, role } }); |
There was a problem hiding this comment.
NoSQL Injection
Unsanitized input from an HTTP parameter flows into find, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.
Line 219 | CWE-943 | Priority score 821 | Learn more about this vulnerability
Data flow: 10 steps
Step 1 - 5
nodejs-goof/routes/workspaces.js
Line 195 in 8eab186
Step 6 routes/workspaces.js#L219
Step 7 services/webhook-delivery.js#L182
Step 8 - 10
nodejs-goof/services/webhook-delivery.js
Line 183 in 8eab186
| if (actErr) return res.status(400).json({ error: actErr }); | ||
| var workspaceId = req.workspaceId; | ||
| var id = req.params.id; | ||
| Rule.findOne({ _id: id, workspace: workspaceId }).exec(function (err, rule) { |
There was a problem hiding this comment.
NoSQL Injection
Unsanitized input from an HTTP parameter flows into findOne, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.
Line 179 | CWE-943 | Priority score 821 | Learn more about this vulnerability
| if (!workspaceAuth.ROLES_WITH_ADMIN.includes(membership.role)) { | ||
| return res.status(403).json({ error: 'Only owner or admin can add members' }); | ||
| } | ||
| return WorkspaceMember.findOne({ workspace: workspaceId, user: newUser }).exec(); |
There was a problem hiding this comment.
NoSQL Injection
Unsanitized input from an HTTP parameter flows into findOne, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.
Line 204 | CWE-943 | Priority score 821 | Learn more about this vulnerability
Data flow: 8 steps
Step 1 - 5
nodejs-goof/routes/workspaces.js
Line 195 in 8eab186
Step 6 - 8
nodejs-goof/routes/workspaces.js
Line 204 in 8eab186
| if (targetUserId === actorId && membership.role === 'owner') { | ||
| return res.status(400).json({ error: 'Owner cannot remove themselves; transfer ownership first' }); | ||
| } | ||
| return WorkspaceMember.findOneAndDelete({ workspace: workspaceId, user: targetUserId }).exec(); |
There was a problem hiding this comment.
NoSQL Injection
Unsanitized input from an HTTP parameter flows into findOneAndDelete, where it is used in an NoSQL query. This may result in an NoSQL Injection vulnerability.
Line 242 | CWE-943 | Priority score 821 | Learn more about this vulnerability
Data flow: 8 steps
Step 1 - 5
nodejs-goof/routes/workspaces.js
Line 231 in 8eab186
Step 6 - 8
nodejs-goof/routes/workspaces.js
Line 242 in 8eab186
| function validateActions(actions) { | ||
| if (!Array.isArray(actions)) return 'actions must be an array'; | ||
| if (actions.length > MAX_ACTIONS) return 'At most ' + MAX_ACTIONS + ' actions per rule'; | ||
| for (var i = 0; i < actions.length; i++) { |
There was a problem hiding this comment.
Unchecked Input for Loop Condition
The 0 object may not be an array, and its length property may be directly set to huge values by an attacker, which would make this loop iterate too many times. This may lead to a Denial-of-service vulnerability.
Line 44 | CWE-400 | CWE-606 | Priority score 803 | Learn more about this vulnerability
Comment out the pull_request trigger so the pipeline only runs on pushes to main/master and manual dispatch. Made-with: Cursor
Only the npm:adm-zip:20180415 (Zip Slip) vulnerability is ignored, to test visibility in the Snyk Dashboard UI. Made-with: Cursor
- Serve profile images from public/images/profiles with extension allowlist, numeric user ID validation, and path traversal checks - Add express-rate-limit dependency - Enable Snyk Code global exclude for tests/** in .snyk Pre-commit: Snyk Code scan and Snyk Open Source (SCA) scan were run on the repo. Made-with: Cursor
Adds the scaffolding to demo Snyk's per-release-version monitoring story: - scripts/snyk-monitor-release.sh: pushes a monitor snapshot keyed on package.json version via --target-reference, so each release becomes its own indefinitely-monitored target in the Snyk dashboard. - scripts/snyk-compliance-report.sh: generates auditor-friendly per-version vuln reports (JSON + markdown) for compliance evidence. - scripts/setup-demo-release-branches.sh: one-shot helper that creates release/v1.0..v2.0 branches from historical commits with pinned versions. - .github/workflows/snyk-release-monitor.yml: release-tag-driven monitor job plus weekly heartbeat for legacy versions to defeat stale-project auto-deactivation. - docs/proconex-demo.md: runbook for the customer meeting. Co-authored-by: Cursor <cursoragent@cursor.com>
Trigger fresh security scan on PR #31 Co-authored-by: Cursor <cursoragent@cursor.com>
| res.setHeader('X-Content-Type-Options', 'nosniff'); | ||
| const userInput = req.query.input; | ||
|
|
||
| res.send(` |
There was a problem hiding this comment.
Cross-site Scripting (XSS)
Unsanitized input from an HTTP parameter flows into send, where it is used to render an HTML page returned to the user. This may result in a Cross-Site Scripting attack (XSS).
Line 11 | CWE-79 | Priority score 553 | Learn more about this vulnerability
Data flow: 8 steps
Step 1 - 5
nodejs-goof/routes/xss-vulnerable.js
Line 9 in 4d82111
Step 6 routes/xss-vulnerable.js#L32
Step 7 - 8
nodejs-goof/routes/xss-vulnerable.js
Line 11 in 4d82111
⚡ Refresh the page to see if a fix suggestion is available 🔄
There was a problem hiding this comment.
⚡ Snyk Agent Fix suggestion 1 of 1
The Cross-site Scripting (XSS) vulnerability was fixed by sanitizing the user input with sanitizeHtml before embedding it into the HTML response.
Code changes
--- routes/xss-vulnerable.js
+++ routes/xss-vulnerable.js
@@ -6,7 +6,7 @@
// SECURE: Safe endpoint with proper HTML escaping
router.get('/secure', (req, res) => {
// Get user input from query parameter
- const userInput = req.query.input;
+ const userInput = sanitizeHtml(req.query.input);
res.send(`
<!DOCTYPE html>
Content generated by AI, expires on 2026-09-02 17:56:05 UTC. Refresh the page after running Snyk commands.
Commands
- ✅ To apply this fix and create a commit - reply with
@snyk /apply 1
No description provided.