265. Path::strip_prefix — Compare Paths by Component, Not by Character
Checking path_str.starts_with("/srv/uploads") says yes to /srv/uploads-old too. Paths need component-wise comparison — and Path has it built in.
The string trap
This morning’s bite 264 showed join silently discarding your base. Here’s the sibling mistake: checking containment with string prefixes.
| |
/srv/uploads-old is a completely different directory, but as a string it starts with /srv/uploads. Any allowlist built on string prefixes has this hole.
The component-aware way
Path::starts_with compares whole components, so a partial directory name never matches:
| |
And when you also want the remainder — for display, for re-joining elsewhere — strip_prefix returns it as a relative path instead of a boolean:
| |
Still lexical
Like everything in std::path, this is pure component comparison — nothing touches the filesystem. That means .. is just another component:
| |
So starts_with alone is not a traversal guard. Validate components before joining (see bite 264), or canonicalize both sides first — then starts_with on the resolved paths is the real containment check.