"Both sides validate. Recall resolves an allowlisted DB path; Ashen Reel independently checks the returned canonical file and root before opening."
Two Checks, Not One
When the deep link arrives, Ashen Reel doesn't open anything yet. It queries its configured loopback Recall service — a fixed local base URL that the incoming link cannot override — and asks Recall to turn the video_id into a real path. Recall does its job: it looks the id up in its database and returns a path it has already allowlisted. That could be the end of the story. It isn't.
Ashen Reel then validates the path again, on its own side of the boundary. It canonicalizes the returned file, confirms it's a real regular file, and checks that — after every symlink is resolved — it still lives inside a configured Recall media root. Only then does it open. Two independent parties each check, because either one alone is a single point of failure.
The Symlink Escape
Here's the subtle attack that 'is this path inside my folder?' misses if you do it naively. Suppose an allowed root contains a symlink pointing out to somewhere sensitive. A string-prefix check on the literal path says "yes, it starts with the allowed root" and waves it through — even though following the link lands outside. The fix is order-of-operations: resolve symlinks first, then check containment. You verify where the path actually leads, not where it superficially claims to be.
.. segments, symlinks, or encoding tricks. Resolve the path to its real, absolute, symlink-free form first; compare that. A comparison is only as trustworthy as the canonicalization in front of it.The independent re-check is short, and the order of the two steps is the whole security:
Why the App Owns the Base URL
One more quiet defense: the loopback Recall address Ashen Reel talks to is its own configured value, never a field in the incoming link. If the URL could say "resolve this id against http://evil.example/api," the attacker would supply the answers to the very lookup meant to constrain them. So the base URL isn't negotiable — the link names a video, and the app alone decides which trusted service resolves it. Every place the attacker might have inserted themselves is a place the design took off the table.