alibaba/nacos · error · NacosException

SERVER_ERROR

SERVER_ERROR

Error message

Downloaded ZIP contains unsafe entry paths: %s

What it means

Thrown by AiHttpClientProxy.downloadSkillZip after SkillUtils.validateZipEntryPaths detects an unsafe (zip-slip or otherwise malicious) entry path in the downloaded skill ZIP. validateZipBytes already confirmed non-empty content; this second guard blocks path-traversal entries that could escape the extraction target. SERVER_ERROR reflects a corrupt or malicious server payload.

Source

Thrown at client/src/main/java/com/alibaba/nacos/client/ai/remote/AiHttpClientProxy.java:314

        params.put("namespaceId", namespaceId);
        params.put("name", skillName);
        if (StringUtils.isNotBlank(version)) {
            params.put("version", version);
        }
        if (StringUtils.isNotBlank(label)) {
            params.put("label", label);
        }
        
        RequestResource resource = RequestResource.aiBuilder().setNamespace(namespaceId)
            .setGroup(com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP)
            .setResource(null == skillName ? StringUtils.EMPTY : skillName).build();
        
        byte[] zipBytes = reqApiBytes(SKILL_DOWNLOAD_PATH, params, resource);
        SkillUtils.validateZipBytes(zipBytes);
        try {
            SkillUtils.validateZipEntryPaths(zipBytes);
        } catch (Exception e) {
            throw new NacosException(NacosException.SERVER_ERROR,
                "Downloaded ZIP contains unsafe entry paths: " + e.getMessage(), e);
        }
        return zipBytes;
    }
    
    @Override
    public SkillQueryResponse querySkill(String skillName, String version, String label, String md5)
        throws NacosException {
        Map<String, String> params = new HashMap<>(8);
        params.put("namespaceId", namespaceId);
        params.put("name", skillName);
        if (StringUtils.isNotBlank(version)) {
            params.put("version", version);
        }
        if (StringUtils.isNotBlank(label)) {
            params.put("label", label);
        }
        if (StringUtils.isNotBlank(md5)) {

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Inspect the downloaded ZIP entries to confirm which path triggered the guard (the exception message lists them).
  2. Re-publish the skill from a clean, correctly-packaged build that uses relative, in-bounds entry paths.
  3. If untrusted, do not extract; quarantine the package and audit the skill source.
  4. Ensure the skill build tooling normalizes entry paths before zipping.

Example fix

// before: skill built with absolute/traversal entry names
// after: build with normalized relative paths, e.g.
//   zip entries like "skills/my-skill/manifest.json" (no leading / or ../)
Defensive patterns

Strategy: validation

Validate before calling

// Before publishing a skill, validate its entries locally:
SkillUtils.validateZipEntryPaths(Files.readAllBytes(Path.of("skill.zip")));

Try / catch

try {
    client.downloadSkillZip(name, version, label);
} catch (NacosException e) {
    if (e.getErrCode() == NacosException.SERVER_ERROR
        && e.getMessage().contains("unsafe entry paths")) {
        // do not extract; quarantine and republish with normalized entry paths
    }
    throw e;
}

Prevention

When it happens

Trigger: The server returns a skill ZIP containing an entry whose path traverses outside the intended directory (e.g. ../../etc/passwd) or otherwise violates the safe-path contract; SkillUtils.validateZipEntryPaths raises and the client wraps it.

Common situations: A tampered or maliciously crafted skill package on the server; a packaging bug in the skill build that emitted absolute or traversal paths; server-side zip assembly regression producing invalid entry names.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/ca2ef73b8491abec. Report an issue: GitHub.