elunez/eladmin · error · BadRequestException

文件只能上传在opt目录或者home目录

Error message

文件只能上传在opt目录或者home目录 

What it means

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.

Source

Thrown at eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/AppServiceImpl.java:95

    @Transactional(rollbackFor = Exception.class)
    public void update(App resources) {
        // 验证应用名称是否存在恶意攻击payload,https://github.com/elunez/eladmin/issues/873
        String appName = resources.getName();
        if (appName.contains(";") || appName.contains("|") || appName.contains("&")) {
            throw new IllegalArgumentException("非法的应用名称,请勿包含[; | &]等特殊字符");
        }
        verification(resources);
        App app = appRepository.findById(resources.getId()).orElseGet(App::new);
        ValidationUtil.isNull(app.getId(),"App","id",resources.getId());
        app.copy(resources);
        appRepository.save(app);
    }

    private void verification(App resources){
        String opt = "/opt";
        String home = "/home";
        if (!(resources.getUploadPath().startsWith(opt) || resources.getUploadPath().startsWith(home))) {
            throw new BadRequestException("文件只能上传在opt目录或者home目录 ");
        }
        if (!(resources.getDeployPath().startsWith(opt) || resources.getDeployPath().startsWith(home))) {
            throw new BadRequestException("文件只能部署在opt目录或者home目录 ");
        }
        if (!(resources.getBackupPath().startsWith(opt) || resources.getBackupPath().startsWith(home))) {
            throw new BadRequestException("文件只能备份在opt目录或者home目录 ");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<Long> ids) {
        for (Long id : ids) {
            appRepository.deleteById(id);
        }
    }

    @Override

View on GitHub (pinned to 55fbf70595)

Solutions

  1. Change uploadPath to a directory under /opt or /home (e.g. /opt/eladmin/upload) and resubmit.
  2. Create that directory on the target server and give the service user write permission.
  3. 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.
  4. Ensure the path starts with a leading '/' — relative paths fail the check.

Example fix

// before
app.setUploadPath("/var/upload"); // -> 400

// after
app.setUploadPath("/opt/eladmin/upload");
Defensive patterns

Strategy: validation

Validate before calling

// Validate the path against the server whitelist before submit
String upload = form.getUploadPath();
if (upload == null || !(upload.startsWith("/opt") || upload.startsWith("/home"))) {
    throw new IllegalArgumentException("uploadPath must be under /opt or /home");
}
appService.create(form);

Type guard

boolean isWhitelistedPath(String p) {
    return p != null && (p.startsWith("/opt") || p.startsWith("/home"));
}

Try / catch

try {
    appService.create(app);
} catch (BadRequestException e) {
    if (e.getMessage().contains("只能上传在")) { showPathRuleError("uploadPath"); return; }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of elunez/eladmin@55fbf70595 (2026-08-14). Data as JSON: /api/errors/007c48999e755253. Report an issue: GitHub.