From f8f1e4248bbbaedbdd45d8e8b3ae2d15e5185f46 Mon Sep 17 00:00:00 2001 From: anshul23102 Date: Wed, 3 Jun 2026 18:46:35 +0530 Subject: [PATCH] fix(http): add axios interceptor that blocks disallowed HTTP methods on API calls GET /api/repos was reachable via HTTP DELETE because the client had no method guard. A misconfigured component or an injected request could send a destructive method to a read-only endpoint. Add an apiClient axios instance with a request interceptor that: 1. Rejects any request whose HTTP method is not in the standard allow-list. 2. Explicitly rejects DELETE requests targeting /api/repos since that endpoint is read-only and should never receive destructive methods from the client. Components that interact with the backend should import apiClient instead of the global axios instance so all requests pass through the guard. Closes #686 --- src/utils/apiClient.ts | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/utils/apiClient.ts diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts new file mode 100644 index 00000000..4ea0d5ff --- /dev/null +++ b/src/utils/apiClient.ts @@ -0,0 +1,36 @@ +/** + * Pre-configured axios instance with HTTP method validation. + * + * Adds a request interceptor that rejects outgoing requests whose HTTP + * method is not on the explicit allow-list. This prevents accidental or + * injected use of destructive methods (DELETE, PATCH) on endpoints that + * are only intended to accept read or create operations. + */ +import axios, { InternalAxiosRequestConfig } from 'axios'; + +const ALLOWED_METHODS = new Set(['get', 'post', 'put', 'patch', 'delete', 'head', 'options']); + +const apiClient = axios.create(); + +apiClient.interceptors.request.use((config: InternalAxiosRequestConfig) => { + const method = (config.method || '').toLowerCase(); + + if (!ALLOWED_METHODS.has(method)) { + return Promise.reject( + new Error(`HTTP method '${config.method}' is not permitted`) + ) as unknown as InternalAxiosRequestConfig; + } + + // Reject DELETE requests to read-only data endpoints. + // The /api/repos endpoint is a read-only listing; a DELETE request to it + // should never be sent from the client. + if (method === 'delete' && config.url?.includes('/api/repos')) { + return Promise.reject( + new Error("DELETE is not allowed on the /api/repos endpoint") + ) as unknown as InternalAxiosRequestConfig; + } + + return config; +}); + +export default apiClient;