You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
icp-project: loading a project does not confine the paths its manifest names #865
icp project bundle checks that every path a manifest names resolves inside the project (SourceEscapesProject, EnvVarEscapesProject, ImageEscapesProject, DependencyOutsideWorkspace in operations/bundle.rs). Loading a project does not: project.rs joins each manifest path onto its base directory and reads it through the FileSystem it is given, and HostFileSystem is the plain disk with no root.
That is the right behaviour for the CLI, where the project is the user's own tree and reading ../shared/args.bin is a feature. It is the wrong behaviour for a project that came from somewhere else: a bundle handed to a deploy service by an agent, for example. There, a manifest can name ../../etc/hostname (or an absolute path) as an init_args file or an environment-variable file, and the loader reads it into the project model during consolidate_manifest, before any caller can inspect the loaded project. The contents then leave the machine at install, as the canister's arguments or settings.
Why the fix belongs in the loader
A consumer could re-implement the manifest discovery (canister globs, per-canister manifests, argument and variable files, dependency projects by path:) to validate paths before loading, but that duplicates the loader and has to track every upstream field that holds a path. The loader already resolves every path through one seam, the FileSystem trait, so confinement at that seam covers all of them at once.
Proposed change
A files::Confined filesystem: the host filesystem held to one directory. Every path is resolved against the root before the disk sees it (relative paths joined, . dropped, .. applied), and a path that comes to rest outside the root, by climbing, by being absolute elsewhere, or through a symlink inside the root that points out, is refused. Predicates answer false for such paths, scratch directories are made under the root, and resolve hands out the real path for callers that need one outside the trait (a wasm runtime mounting a directory).
Nothing changes for the CLI, which keeps using HostFileSystem. A host that loads a project from elsewhere hands the loader a Confined instead.
Context
Motivated by dfinity/imcp2#230, which deploys icp project bundle archives through icp-project from an MCP server and currently carries its own index-backed filesystem to get this guarantee.
Activity
feat(project): an untrusted project is held to the shape a bundle has
feat(project): an untrusted project is held to the shape a bundle has
feat(project): an untrusted project is held to the shape a bundle has
feat(project): an untrusted project is held to the shape a bundle has