From 840a35da853819f1dfb76cbed7e2f6cf237b3865 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 17:54:15 +0000 Subject: [PATCH] Fix command injection and flag injection in `docker-logs` API Replaces `execSync` with `execFileSync` to properly handle array-based arguments and validate input parameters starting with hyphens. Also sanitizes the internal stack traces exposed to the frontend in case of a crash or failure. Co-authored-by: bobdivx <6737167+bobdivx@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ src/pages/api/docker-logs.ts | 18 +++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 00000000..9def09c4 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-05-13 - Command Injection in Docker Logs via URL Parameters +**Vulnerability:** Command injection and potential flag injection due to using `execSync` with unsanitized URL parameters (`tail` and `id`) string-concatenated in `docker logs`. +**Learning:** Even internal toolings or APIs querying basic container information can be vectors for critical command injections if parameters derived from `url.searchParams` are concatenated into strings executed by the shell. +**Prevention:** Always use `execFileSync`, `execFile`, or `spawn` with an array of arguments, and ensure input parameters do not start with a hyphen (`-`) to mitigate flag injection vulnerabilities in CLI tools like docker. Also, catch blocks should sanitize error outputs rather than throwing raw internal stack traces directly. diff --git a/src/pages/api/docker-logs.ts b/src/pages/api/docker-logs.ts index cb72e09e..aa841b5d 100644 --- a/src/pages/api/docker-logs.ts +++ b/src/pages/api/docker-logs.ts @@ -1,5 +1,5 @@ import type { APIRoute } from 'astro'; -import { execSync } from 'child_process'; +import { execFileSync } from 'child_process'; export const GET: APIRoute = async ({ url }) => { try { @@ -21,18 +21,25 @@ export const GET: APIRoute = async ({ url }) => { }); } + // Validation des entrées pour éviter l'injection de flags + if (containerId.startsWith('-') || tail.startsWith('-')) { + return new Response(JSON.stringify({ error: "Paramètres invalides" }), { + status: 400, + headers: { 'Content-Type': 'application/json' } + }); + } + // Commande Docker pour récupérer les logs - const command = `docker logs --tail ${tail} ${containerId}`; let logs = []; try { - const output = execSync(command, { stdio: ['pipe', 'pipe', 'pipe'] }).toString(); + const output = execFileSync('docker', ['logs', '--tail', tail, containerId], { stdio: ['pipe', 'pipe', 'pipe'], encoding: 'utf8' }); logs = output.trim().split('\n'); } catch (err: any) { // Certains logs sortent sur stderr, checkons stderr si stdout est vide ou si erreur if (err.stderr) { logs = err.stderr.toString().trim().split('\n'); } else { - throw err; + throw new Error("Erreur d'exécution de la commande"); } } @@ -41,7 +48,8 @@ export const GET: APIRoute = async ({ url }) => { headers: { 'Content-Type': 'application/json' } }); } catch (error: any) { - return new Response(JSON.stringify({ error: "Logs indisponibles: " + error.message }), { + // Ne pas fuiter les stack traces internes + return new Response(JSON.stringify({ error: "Logs indisponibles" }), { status: 500, headers: { 'Content-Type': 'application/json' } });