#60 Build-time path traversal: forge frontmatter id/version writes outside the output dir
hu13 build writes forge pages using frontmatter values as path segments without validation, so a repo can write arbitrary files outside the output directory.
Reproductions (all verified on master):
# .forge/issues/aaaa/issue.md with id: ../../../../../../tmp/PWNED
$ hu13 build . -o /tmp/trav-out
$ ls /tmp/PWNED.html
-rw-r--r-- 1 z z 1870 /tmp/PWNED.html
# .forge/prs/bbbb/pr.md with id: ../../../../../../tmp/PWNED2 -> /tmp/PWNED2.html
# .forge/releases/r1.md with version: /tmp/PWNED3 -> /tmp/PWNED3.html
Root causes:
forge::render_loaded->write_page(out, &format!("issues/{}.html", issue.id))and the same forpulls/{}.html.issue.id/pr.idcome straight from frontmatter (fm.id) and are never validated.releases::render_loaded->out.join("releases").join(format!("{}.html", rel.version)).releases::loadguards artifacts against/,\,.., butfm.versionitself is unvalidated — andPath::joinwith an absolute component discardsoutentirely.
Impact: build runs in CI/Docker and writes with its own permissions. A hostile PR (or a repo you mirror but do not control) can drop attacker-influenced HTML anywhere the build user can write: overwrite other build outputs, plant files in a served tree, clobber dotfiles/config in the workspace. Because the content is a full issue/PR page, the body text is attacker-controlled (escaped HTML, but still attacker-chosen bytes and filename).
Fix:
- validate every frontmatter-used-as-path value: issue/pr
idmust match^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$(the f0rge uuid shape), releaseversionmust reject/,\, absolute paths and..components - defense in depth: one
write_pagehelper that rejects anyrelcontaining a..component or an absolute prefix, and asserts the final path stays underout - tests: traversal fixtures for issue id, pr id, release version; build must fail (or skip) and must not create the outside file
Note: this predates #54 and is independent of it. It is the most serious finding of the review so far.
Uunknown ·
Fixed in 44ea71b1 (ff 1c7055f). Ids/versions validated at load; write_page() refuses unsafe relative paths; tests/path_safety.rs covers issue id, PR id, absolute release version and '..' traversal.