{"record":{"id":"007c48999e755253","repo":"elunez/eladmin","slug":"opt-home","errorCode":null,"errorMessage":"文件只能上传在opt目录或者home目录 ","messagePattern":"文件只能上传在opt目录或者home目录 ","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/AppServiceImpl.java","lineNumber":95,"sourceCode":"    @Transactional(rollbackFor = Exception.class)\n    public void update(App resources) {\n        // 验证应用名称是否存在恶意攻击payload，https://github.com/elunez/eladmin/issues/873\n        String appName = resources.getName();\n        if (appName.contains(\";\") || appName.contains(\"|\") || appName.contains(\"&\")) {\n            throw new IllegalArgumentException(\"非法的应用名称，请勿包含[; | &]等特殊字符\");\n        }\n        verification(resources);\n        App app = appRepository.findById(resources.getId()).orElseGet(App::new);\n        ValidationUtil.isNull(app.getId(),\"App\",\"id\",resources.getId());\n        app.copy(resources);\n        appRepository.save(app);\n    }\n\n    private void verification(App resources){\n        String opt = \"/opt\";\n        String home = \"/home\";\n        if (!(resources.getUploadPath().startsWith(opt) || resources.getUploadPath().startsWith(home))) {\n            throw new BadRequestException(\"文件只能上传在opt目录或者home目录 \");\n        }\n        if (!(resources.getDeployPath().startsWith(opt) || resources.getDeployPath().startsWith(home))) {\n            throw new BadRequestException(\"文件只能部署在opt目录或者home目录 \");\n        }\n        if (!(resources.getBackupPath().startsWith(opt) || resources.getBackupPath().startsWith(home))) {\n            throw new BadRequestException(\"文件只能备份在opt目录或者home目录 \");\n        }\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void delete(Set<Long> ids) {\n        for (Long id : ids) {\n            appRepository.deleteById(id);\n        }\n    }\n\n    @Override","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/elunez/eladmin/blob/55fbf705956949697dbd68bf9003776609d3d029/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/AppServiceImpl.java#L77-L113","documentation":"AppServiceImpl.verification (called from create/update) enforces that App.uploadPath starts with '/opt' or '/home'; otherwise BadRequestException('文件只能上传在opt目录或者home目录 '). The whitelist restricts where uploaded deploy packages may be written on the server, limiting path-traversal/arbitrary-write risk.","triggerScenarios":"POST/PUT /api/app with uploadPath like '/tmp/pkg', 'D:\\deploy', '/var/www/upload', or 'root/...' — any path not starting with the literal prefixes '/opt' or '/home'. Note '/opt123' would pass (startsWith), while 'opt/app' (no leading slash) fails.","commonSituations":"Migrating configs from servers using /var or /data; Windows-style paths in dev; missing leading slash typos; security hardening reviews testing whether arbitrary paths are accepted.","solutions":["Change uploadPath to a directory under /opt or /home (e.g. /opt/eladmin/upload) and resubmit.","Create that directory on the target server and give the service user write permission.","If another root is mandatory, extend verification() (and its deploy/backup siblings) to accept an explicit configured whitelist — treat as a security change, review it.","Ensure the path starts with a leading '/' — relative paths fail the check."],"exampleFix":"// before\napp.setUploadPath(\"/var/upload\"); // -> 400\n\n// after\napp.setUploadPath(\"/opt/eladmin/upload\");","handlingStrategy":"validation","validationCode":"// Validate the path against the server whitelist before submit\nString upload = form.getUploadPath();\nif (upload == null || !(upload.startsWith(\"/opt\") || upload.startsWith(\"/home\"))) {\n    throw new IllegalArgumentException(\"uploadPath must be under /opt or /home\");\n}\nappService.create(form);","typeGuard":"boolean isWhitelistedPath(String p) {\n    return p != null && (p.startsWith(\"/opt\") || p.startsWith(\"/home\"));\n}","tryCatchPattern":"try {\n    appService.create(app);\n} catch (BadRequestException e) {\n    if (e.getMessage().contains(\"只能上传在\")) { showPathRuleError(\"uploadPath\"); return; }\n    throw e;\n}","preventionTips":["Standardize on one whitelisted root (e.g. /opt/<team>) for all App paths.","Add a leading-slash check in the UI form; relative paths always fail.","Pre-create the directories with correct ownership before registering the App."],"tags":["security","path-validation","eladmin","app-management","configuration"],"backgroundTag":null,"analyzedSha":"55fbf705956949697dbd68bf9003776609d3d029","analyzedAt":"2026-08-14T11:56:12.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}