From 5dd53eb9a00259cb0a09b345ba30b1feb2470f4a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 20:05:15 +0000 Subject: [PATCH] Secure API endpoints against HTTP Parameter Pollution and Path Traversal Wrapped dynamic user inputs in `encodeURIComponent()` within `src/services/apiService.js` to prevent malicious character injection, mitigating Path Traversal and HTTP Parameter Pollution vulnerabilities. Co-authored-by: belpythons <187399139+belpythons@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ src/services/apiService.js | 30 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..a9cc519 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-05-10 - Secure API Service Endpoints against HTTP Parameter Pollution and Path Traversal +**Vulnerability:** Dynamic variables were interpolated directly into template literals for API endpoints without encoding, which could allow malicious users to inject special characters to manipulate the URL path (Path Traversal) or add additional query parameters (HTTP Parameter Pollution). +**Learning:** It is crucial to always encode user-supplied or dynamic input when constructing URLs, even for internal API calls, to prevent injection attacks that alter the intended request structure. +**Prevention:** Use `encodeURIComponent()` consistently for all dynamic path segments and query parameters within template literals when building API requests. \ No newline at end of file diff --git a/src/services/apiService.js b/src/services/apiService.js index b8e3b23..3132c93 100644 --- a/src/services/apiService.js +++ b/src/services/apiService.js @@ -3,25 +3,25 @@ import api from './api'; // Roadmaps API export const roadmapsApi = { getAll: () => api.get('/roadmaps'), - getById: (id) => api.get(`/roadmaps/${id}`), + getById: (id) => api.get(`/roadmaps/${encodeURIComponent(id)}`), }; // Topics API export const topicsApi = { - getByRoadmapId: (roadmapId) => api.get(`/topics/roadmap/${roadmapId}`), - getById: (id) => api.get(`/topics/${id}`), + getByRoadmapId: (roadmapId) => api.get(`/topics/roadmap/${encodeURIComponent(roadmapId)}`), + getById: (id) => api.get(`/topics/${encodeURIComponent(id)}`), }; // Lessons API export const lessonsApi = { - getByTopicId: (topicId) => api.get(`/lessons/topic/${topicId}`), - getById: (id) => api.get(`/lessons/${id}`), + getByTopicId: (topicId) => api.get(`/lessons/topic/${encodeURIComponent(topicId)}`), + getById: (id) => api.get(`/lessons/${encodeURIComponent(id)}`), }; // Progress API export const progressApi = { getAll: () => api.get('/progress'), - getByRoadmapId: (roadmapId) => api.get(`/progress/roadmap/${roadmapId}`), + getByRoadmapId: (roadmapId) => api.get(`/progress/roadmap/${encodeURIComponent(roadmapId)}`), markComplete: (lessonId) => api.post('/progress/complete', { lessonId }), markIncomplete: (lessonId) => api.post('/progress/incomplete', { lessonId }), }; @@ -29,23 +29,23 @@ export const progressApi = { // Notes API export const notesApi = { getAll: () => api.get('/notes'), - getByLessonId: (lessonId) => api.get(`/notes/lesson/${lessonId}`), + getByLessonId: (lessonId) => api.get(`/notes/lesson/${encodeURIComponent(lessonId)}`), create: (data) => api.post('/notes', data), - update: (id, data) => api.put(`/notes/${id}`, data), - delete: (id) => api.delete(`/notes/${id}`), + update: (id, data) => api.put(`/notes/${encodeURIComponent(id)}`, data), + delete: (id) => api.delete(`/notes/${encodeURIComponent(id)}`), }; // Comments API export const commentsApi = { - getByLessonId: (lessonId) => api.get(`/comments/lesson/${lessonId}`), + getByLessonId: (lessonId) => api.get(`/comments/lesson/${encodeURIComponent(lessonId)}`), create: (data) => api.post('/comments', data), - update: (id, data) => api.put(`/comments/${id}`, data), - delete: (id) => api.delete(`/comments/${id}`), + update: (id, data) => api.put(`/comments/${encodeURIComponent(id)}`, data), + delete: (id) => api.delete(`/comments/${encodeURIComponent(id)}`), }; // Search API export const searchApi = { - search: (query) => api.get(`/search?q=${query}`), + search: (query) => api.get(`/search?q=${encodeURIComponent(query)}`), }; // Auth API @@ -65,7 +65,7 @@ export const aboutApi = { }; export const contactApi = { - send: (data) => Promise.resolve({ data: { success: true } }), + send: (_data) => Promise.resolve({ data: { success: true } }), }; export const documentariesApi = { @@ -78,5 +78,5 @@ export const forumsApi = { export const postsApi = { getAll: () => Promise.resolve({ data: [] }), - getById: (id) => Promise.resolve({ data: {} }), + getById: (_id) => Promise.resolve({ data: {} }), };