Skip to content

abcd site build writes are os.Root-contained; reads still follow a committed directory symlink #487

Description

@jogrun

What

internal/core/site/build.go:8-10 says nothing writes outside the output directory: every write goes through os.Root at dest. Reads do not get the matching containment.

loadPage (internal/core/site/compose.go:88) is:

fsutil.ReadGuarded(joinRepo(c.repoRoot, rel), maxPageBytes)

ReadGuarded is leaf O_NOFOLLOW only. A committed directory symlink (docs/explanation -> ../../.ssh, git mode 120000) is a valid relative path: ValidRelPath accepts it, Join walks through the ancestor, ReadGuarded opens the leaf inside the target, and the bytes can be composed into published HTML.

The same joinRepo + ReadGuarded shape is in explorer.go:130, assets.go (raster/SVG copy), recordpage.go:121, foundations.go:75.

Positioning already treats this as the attack (internal/core/positioning/containment_test.go:17-25) and uses ReadGuardedInRoot. Site did not.

Suggested fix

Open os.Root at the repo root for site reads and use ReadGuardedInRoot (or equivalent) for every joinRepo content read. Port or share positioning's hostile-repo fixture (absolute etclink -> /etc and relative home -> ../../..). Assert the containment canary never appears in a composed page.

Happy to send a PR once this is accepted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions