{"record":{"id":"ae2670e041371793","repo":"coollabsio/coolify","slug":"invalid-dockerfile-target-build-contains-forbidde","errorCode":null,"errorMessage":"Invalid dockerfile_target_build: contains forbidden characters.","messagePattern":"Invalid dockerfile_target_build: contains forbidden characters\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"app/Jobs/ApplicationDeploymentJob.php","lineNumber":353,"sourceCode":"                        if (preg_match('/-(\\d{12})/', $containerName)) {\n                            continue;\n                        }\n                        $containerIp = data_get($container, 'IPv4Address');\n                        if ($containerName && $containerIp) {\n                            $containerIp = str($containerIp)->before('/');\n                            $ips->put($containerName, $containerIp->value());\n                        }\n                    }\n                }\n                $this->addHosts = $ips->map(function ($ip, $name) {\n                    return \"--add-host $name:$ip\";\n                })->implode(' ');\n            }\n\n            if ($this->application->dockerfile_target_build) {\n                $target = $this->application->dockerfile_target_build;\n                if (! preg_match(ValidationPatterns::DOCKER_TARGET_PATTERN, $target)) {\n                    throw new \\RuntimeException('Invalid dockerfile_target_build: contains forbidden characters.');\n                }\n                $this->buildTarget = \" --target {$target} \";\n            }\n\n            // Check custom port\n            ['repository' => $this->customRepository, 'port' => $this->customPort] = $this->application->customRepository();\n\n            if (data_get($this->application, 'settings.is_build_server_enabled')) {\n                $teamId = data_get($this->application, 'environment.project.team.id');\n                $buildServers = Server::buildServers($teamId)->get();\n                if ($buildServers->count() === 0) {\n                    $this->application_deployment_queue->addLogEntry('No suitable build server found. Using the deployment server.');\n                    $this->build_server = $this->server;\n                } else {\n                    $this->build_server = $buildServers->random();\n                    $this->application_deployment_queue->build_server_id = $this->build_server->id;\n                    $this->application_deployment_queue->addLogEntry(\"Found a suitable build server ({$this->build_server->name}).\");\n                    $this->use_build_server = true;","sourceCodeStart":335,"sourceCodeEnd":371,"githubUrl":"https://github.com/coollabsio/coolify/blob/70b9acc42467278373e00de77abb40684e25b395/app/Jobs/ApplicationDeploymentJob.php#L335-L371","documentation":"During deployment, ApplicationDeploymentJob interpolates application->dockerfile_target_build into the docker build --target argument. Before doing so it validates the value against ValidationPatterns::DOCKER_TARGET_PATTERN (/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/): it must start alphanumeric and contain only letters, digits, dots, hyphens, underscores. Anything else — leading . or -, spaces, $, quotes, unicode — throws, protecting the shell command from injection.","triggerScenarios":"Deploying an application whose 'Build Target' (dockerfile_target_build) field holds e.g. '.prod', '-builder', 'builder stage', 'prod$(whoami)', or any value copied with a space/quote; the field was set via UI or API without passing the same regex rule.","commonSituations":"Copy-pasting a stage name with whitespace; using shell-style variable names like $TARGET; older records saved before this validation existed now failing on redeploy.","solutions":["Set the Build Target field to a plain stage name that starts with a letter or digit, e.g. 'builder' or 'production' (letters, digits, . _ - only after the first char).","Rename the corresponding stage in your Dockerfile to match the allowed pattern.","Clear the field entirely if you do not need multi-stage targeting.","If storing via API, apply ValidationPatterns::dockerTargetRules() on save so it fails at input time, not deploy time."],"exampleFix":"# before: invalid build target stored on the application\n# Dockerfile stage: FROM node:20 AS builder prod\ndockerfile_target_build: 'builder prod'\n\n# after: rename the stage and use it verbatim\n# Dockerfile: FROM node:20 AS builder-prod\ndockerfile_target_build: 'builder-prod'","handlingStrategy":"validation","validationCode":"// Validate on save (UI/API), not at deploy time\n$validated = $request->validate([\n    'dockerfile_target_build' => ValidationPatterns::dockerTargetRules(), // nullable|string|max:128|regex:/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/\n]);","typeGuard":"function isValidBuildTarget(?string $target): bool\n{\n    return blank($target) || preg_match(\\App\\Support\\ValidationPatterns::DOCKER_TARGET_PATTERN, $target) === 1;\n}","tryCatchPattern":null,"preventionTips":["Apply the same DOCKER_TARGET_PATTERN regex rule where the field is stored, not only in the deployment job.","Offer a dropdown of stage names parsed from the Dockerfile instead of free text.","On redeploy failures, check legacy records: applications whose stored target predates the validation."],"tags":["docker","deployment","build-target","validation","shell-injection"],"backgroundTag":"input-validation-failed","analyzedSha":"70b9acc42467278373e00de77abb40684e25b395","analyzedAt":"2026-08-17T01:41:01.313Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}