{"record":{"id":"969337cbab9702f8","repo":"Crosstalk-Solutions/project-nomad","slug":"guard-blocked-join","errorCode":null,"errorMessage":"guard.blocked.join(' ')","messagePattern":"guard\\.blocked\\.join\\(' '\\)","errorType":"http","errorClass":null,"httpStatus":422,"severity":"error","filePath":"admin/app/controllers/system_controller.ts","lineNumber":400,"sourceCode":"            })\n        }\n\n        // Reject duplicate host ports within the request — Docker would otherwise fail at\n        // start time with an opaque \"port is already allocated\" error.\n        const hostPorts = (payload.ports ?? []).map((p) => p.host)\n        const duplicateHostPorts = [...new Set(hostPorts.filter((p, i) => hostPorts.indexOf(p) !== i))]\n        if (duplicateHostPorts.length) {\n            return response.status(422).send({\n                success: false,\n                message: `Duplicate host port(s): ${duplicateHostPorts.join(', ')}. Each host port can map to only one container.`,\n            })\n        }\n\n        // Security guardrails: hard-block dangerous bind mounts / malformed images regardless of\n        // force; surface overridable warnings (risky paths, untrusted/moving-tag images) unless forced.\n        const guard = evaluateCustomApp({ image: payload.image, volumes: payload.volumes })\n        if (guard.blocked.length) {\n            return response.status(422).send({\n                success: false,\n                message: guard.blocked.join(' '),\n                blocked: guard.blocked,\n            })\n        }\n        if (!payload.force && guard.warnings.length) {\n            return response.status(409).send({\n                success: false,\n                message: guard.warnings.join(' '),\n                warnings: guard.warnings,\n            })\n        }\n\n        // Advisory preflight: surface port conflicts before creating the record so a failed\n        // install doesn't leave a phantom card. The user can re-submit with force=true to override.\n        if (!payload.force && hostPorts.length) {\n            const { conflicts } = await this.dockerService.checkPortConflicts(hostPorts)\n            if (conflicts.length) {","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/Crosstalk-Solutions/project-nomad/blob/0bd1c6f4f9888d577fe232de06ac144bb8337131/admin/app/controllers/system_controller.ts#L382-L418","documentation":"A 422 from createCustomApp when evaluateCustomApp hard-blocks the request. The guard rejects dangerous bind mounts (e.g. mounting / or /var/run/docker.sock) and malformed image references; these blocks cannot be overridden with force=true.","triggerScenarios":"POST create-custom-app with a volume like /:/host or /var/run/docker.sock:/var/run/docker.sock, or an image string that fails reference validation.","commonSituations":"User tries to give an app Docker control via the socket mount, mounts the host root, or typos the image name so it doesn't parse as a valid reference.","solutions":["Read guard.blocked in the response — each entry names the rejected volume/image and why","Remove or narrow the dangerous bind mount (mount only a specific subdirectory)","Fix the image reference to a valid registry/name:tag form","Note: force=true will NOT bypass blocked items by design"],"exampleFix":"// before\nvolumes: [{ host: '/var/run/docker.sock', container: '/var/run/docker.sock' }]\n// after\nvolumes: [{ host: '/opt/myapp/data', container: '/data' }]","handlingStrategy":"validation","validationCode":"const blocked = evaluateCustomApp({ image, volumes }); // if available client-side\nconst dangerous = volumes?.some((v) => /^\\/(var\\/run\\/docker\\.sock|etc|var)?$/.test(v.host));\nif (dangerous) disableSubmit();","typeGuard":"const isSafeMount = (h: string) => !/^\\/(var\\/run\\/docker\\.sock|root|etc|var|bin|sbin|usr|lib)?$/g.test(h);","tryCatchPattern":null,"preventionTips":["Never mount the Docker socket or host root","Remember force cannot bypass blocked items"],"tags":["security","bind-mount","guardrail","docker"],"backgroundTag":"dangerous-bind-mount-blocked","analyzedSha":"0bd1c6f4f9888d577fe232de06ac144bb8337131","analyzedAt":"2026-08-27T05:34:15.424Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}