Skip to content

fix: Manual source upload API allows unauthenticated path traversal write outside#35

Open
jonathanchang31 wants to merge 1 commit into
aglover1221:mainfrom
jonathanchang31:fix/manual-source-upload-api
Open

fix: Manual source upload API allows unauthenticated path traversal write outside#35
jonathanchang31 wants to merge 1 commit into
aglover1221:mainfrom
jonathanchang31:fix/manual-source-upload-api

Conversation

@jonathanchang31
Copy link
Copy Markdown

Summary

Fixes #34 by closing a server-side path traversal in the manual source upload flow.

Before this change, /api/pipeline/sources/upload accepted attacker-controlled docType values and the backend derived the stored filename from that value. Because the write path used the derived filename without a strict basename/boundary check, a crafted multipart request could write a PDF outside PRODUCT_MCP_DATA_DIR.

This change makes stored filenames server-controlled, rejects unsupported docType values at the API boundary, and enforces a resolved-path containment check before any source file write.

Related Issue

Fixed: #34

Change Type

  • Bug fix
  • Security fix
  • API behavior change
  • Test update
  • New feature
  • Breaking change
  • Documentation only
  • Refactor only

Real Behavior Proof

1. Test suite passes

2. Production build passes

npm run build

Observed result:

✓ Compiled successfully
✓ Generating static pages (26/26)

3. Original exploit is now blocked

Replayed the original traversal payload against a fresh isolated runtime:

curl -sS -F 'productSlug=r770' \
  -F 'docType=../../../../../../uploaded_escape' \
  -F 'scope=own' \
  -F 'title=Traversal upload After Fix' \
  -F 'file=@/tmp/pdex-fixcheck-large.pdf;type=application/pdf;filename=poc.pdf' \
  http://localhost:3311/api/pipeline/sources/upload

Observed result:

{"error":"unsupported docType: ../../../../../../uploaded_escape"}

HTTP status:

400

Filesystem result:

  • no escaped file created outside PRODUCT_MCP_DATA_DIR
  • no poisoned sources.yaml
  • no poisoned product markdown entry

4. Valid upload flow still works

Replayed a normal upload:

curl -sS -F 'productSlug=r770' \
  -F 'docType=tech-guide' \
  -F 'scope=own' \
  -F 'title=Valid upload After Fix' \
  -F 'file=@/tmp/pdex-fixcheck-large.pdf;type=application/pdf;filename=poc.pdf' \
  http://localhost:3311/api/pipeline/sources/upload

Observed result:

{"ok":true,"productSlug":"r770","localPath":"server/dell/poweredge/r770/source/technical-guide.pdf", ...}

Filesystem result:

  • file created at server/dell/poweredge/r770/source/technical-guide.pdf
  • sources.yaml updated
  • product markdown frontmatter updated

Security Impact

This fix removes an unauthenticated arbitrary file write primitive from the manual upload endpoint.
Before the patch, a malicious client could escape the intended product source directory and write uploaded files outside PRODUCT_MCP_DATA_DIR. After the patch, only supported document types are accepted and all final write targets are constrained to the intended source directory.

Checklist

  • Reproduced the issue locally before the fix
  • Fixed the vulnerable backend path handling
  • Added regression coverage
  • Verified normal uploads still succeed
  • Verified traversal payload is rejected
  • Ran test suite
  • Ran production build
  • Ran application locally without errors

@jonathanchang31
Copy link
Copy Markdown
Author

@aglover1221 Could you plz review my PR?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Critical: Manual source upload API allows unauthenticated path traversal write outside PRODUCT_MCP_DATA_DIR via docType

1 participant